Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Look into Gtk 4 #267

Open
1 of 39 tasks
Cimbali opened this issue Jan 13, 2023 · 0 comments
Open
1 of 39 tasks

Look into Gtk 4 #267

Cimbali opened this issue Jan 13, 2023 · 0 comments

Comments

@Cimbali
Copy link
Owner

Cimbali commented Jan 13, 2023

Gtk 4 supposedly allows improved handling of media playback, layout managers, and accessibility. However it also introduces a plethora of breaking changes that will probably require a significant rewrite. Furthermore I have no idea if any of the build processes we use (especially on macOS and MinGW) currently support Gtk 4. This issue is more of an inventory of things that would be required to transition to Gtk 4, if we ever do it, than an actual todo list.


From the migrating guide here’s the points that should impact pympress.

Backported in Gtk3:

  • Stop using direct access to GdkEvent structs

    In GTK 4, event structs are opaque and immutable. Many fields already have accessors in GTK 3, and you should use those to reduce the amount of porting work you have to do at the time of the switch.

  • Stop using GtkWidget event signals

    Event controllers and gestures replace event signals in GTK 4.

    Most of them have been backported to GTK 3.x so you can prepare for this change.

    Signal Event controller
    ::event GtkEventControllerLegacy
    ::event-after GtkEventControllerLegacy
    ::button-press-event GtkGestureClick
    ::button-release-event GtkGestureClick
    ::touch-event various touch gestures
    ::scroll-event GtkEventControllerScroll
    ::motion-notify-event GtkEventControllerMotion
    ::delete-event -
    ::key-press-event GtkEventControllerKey
    ::key-release-event GtkEventControllerKey
    ::enter-notify-event GtkEventControllerMotion
    ::leave-notify-event GtkEventControllerMotion
    ::configure-event -
    ::focus-in-event GtkEventControllerFocus
    ::focus-out-event GtkEventControllerFocus
    ::map-event -
    ::unmap-event -
    ::property-notify-event replaced by GdkClipboard
    ::selection-clear-event replaced by GdkClipboard
    ::selection-request-event replaced by GdkClipboard
    ::selection-notify-event replaced by GdkClipboard
    Drag-and-Drop signals GtkDragSource, GtkDropTarget
    ::proximity-in-event GtkGestureStylus
    ::proximity-out-event GtkGestureStylus
    ::visibility-notify-event -
    ::window-state-event -
    ::damage-event -
    ::grab-broken-event -

    Event signals which are not directly related to input have to be dealt with on a one-by-one basis. If you were using ::configure-event and ::window-state-event to save window state, you should use property notification for corresponding GtkWindow properties, such as “default-width”, “default-height”, “maximized” or “fullscreened”.

  • Stop using GtkBox padding, fill and expand child properties

    GTK 4 removes these GtkBox child properties, so you should stop using them. You can replace GtkBox:padding using the “margin” properties on your GtkBox child widgets.

  • Reduce the use of generic container APIs

    GTK 4 removes gtk_container_add() and gtk_container_remove(). While there is not always a replacement for gtk_container_remove() in GTK 3, you can replace many uses of gtk_container_add() with equivalent container-specific APIs such as gtk_box_pack_start() or gtk_grid_attach(), and thereby reduce the amount of work you have to do at the time of the switch.

  • Set a proper application ID

    In GTK 4 we want the application’s GApplication “application-id” (and therefore the D-Bus name), the desktop file basename and Wayland’s xdg-shell app_id to match. In order to achieve this with GTK 3.x call g_set_prgname() with the same application ID you passed to GtkApplication. Rename your desktop files to match the application ID if needed.

    The call to g_set_prgname() can be removed once you fully migrated to GTK 4.

    You should be aware that changing the application ID makes your application appear as a new, different app to application installers. You should consult the appstream documentation for best practices around renaming applications.


To do on transition

  • Subclassing

    Compared to previous versions, GTK 4 emphasizes composition and delegation over subclassing. As a consequence, many widgets can no longer be subclassed. In most cases, you should look deriving your widget directly from GtkWidget and use complex widgets as child widgets instead of deriving from them.

  • Adapt to GdkWindow API changes

    GdkWindow has been renamed to GdkSurface.

    In GTK 4, the two roles of a standalone toplevel window and of a popup that is placed relative to a parent window have been separated out into two interfaces, GdkToplevel and GdkPopup. Surfaces implementing these interfaces are created with gdk_surface_new_toplevel() and gdk_surface_new_popup(), respectively, and they are presented on screen using gdk_toplevel_present() and gdk_popup_present(). The present() functions take parameters in the form of an auxiliary layout struct, GdkPopupLayout or GdkToplevelLayout. If your code is dealing directly with surfaces, you may have to change it to call the API in these interfaces, depending on whether the surface you are dealing with is a toplevel or a popup.

    As part of this reorganization, X11-only concepts such as sticky, keep-below, urgency, skip-taskbar or window groups have either been removed or moved to X11 backend api. If you need to use them on your X11 windows, you will have to use those backend apis or set the corresponding X11 properties (as specified in the EWMH) yourself.

    Subsurfaces are only supported with the Wayland backend, using gdk_wayland_surface_new_subsurface(). Native and foreign subwindows are no longer supported. These concepts were complicating the code and could not be supported across backends.

    A number of GdkWindow APIs are no longer available. This includes gdk_window_reparent(), gdk_window_set_geometry_hints(), gdk_window_raise(), gdk_window_restack(), gdk_window_move(), gdk_window_resize(). If you need to manually control the position or stacking of your X11 windows, you you will have to use Xlib apis.

    A number of minor API cleanups have happened in GdkSurface as well. For example, gdk_surface_input_shape_combine_region() has been renamed to gdk_surface_set_input_region(), and gdk_surface_begin_resize_drag() has been renamed to gdk_toplevel_begin_resize().

  • Life-cycle handling

    Widgets in GTK 4 are treated like any other objects - their parent widget holds a reference on them, and GTK holds a reference on toplevel windows. gtk_window_destroy() will drop the reference on the toplevel window, and cause the whole widget hierarchy to be finalized unless there are other references that keep widgets alive.

    The “destroy” signal is emitted when a widget is disposed, and therefore can no longer be used to break reference cycles. A typical sign of a reference cycle involving a toplevel window is when closing the window does not make the application quit.

  • Stop using GdkScreen

    The GdkScreen object has been removed in GTK 4. Most of its APIs already had replacements in GTK 3 and were deprecated, a few remaining replacements have been added to GdkDisplay.

  • The “iconified” window state has been renamed to “minimized”

    The GDK_TOPLEVEL_STATE_ICONIFIED value of the GdkSurfaceState enumeration is now GDK_TOPLEVEL_STATE_MINIMIZED in the GdkToplevelState enumeration.

    The GdkWindow functions gdk_window_iconify() and gdk_window_deiconify() have been renamed to gdk_toplevel_minimize() and gdk_toplevel_present(), respectively.

    The behavior of the minimization and unminimization operations have not been changed, and they still require support from the underlying windowing system.

  • Adapt to GdkEvent API changes

    Direct access to GdkEvent structs is no longer possible in GTK 4. GdkEvent is now a strictly read-only type, and you can no longer change any of its fields, or construct new events. All event fields have accessors that you will have to use.

    Event compression is always enabled in GTK 4, for both motion and scroll events. If you need to see the uncoalesced motion or scroll history, use gdk_event_get_history() on the latest event.

  • Stop using grabs

    GTK 4 no longer provides the gdk_device_grab() or gdk_seat_grab() apis. If you need to dismiss a popup when the user clicks outside (the most common use for grabs), you can use the GdkPopup “autohide” property instead. GtkPopover also has a “autohide” property for this. If you need to prevent the user from interacting with a window while a dialog is open, use the “modal” property of the dialog.

  • Adapt to coordinate API changes

    A number of coordinate APIs in GTK 3 had _double variants: gdk_device_get_surface_at_position(), gdk_surface_get_device_position(). These have been changed to use doubles, and the _double variants have been removed. Update your code accordingly.

    Any APIs that deal with global (or root) coordinates have been removed in GTK 4, since not all backends support them. You should replace your use of such APIs with surface-relative equivalents. Examples of this are gdk_surface_get_origin(), gdk_surface_move() or gdk_event_get_root_coords().

  • Adapt to changes in keyboard modifier handling

    GTK 3 has the idea that use of modifiers may differ between different platforms, and has a GdkModifierIntent api to let platforms provide hint about how modifiers are expected to be used. It also promoted the use of <Primary> instead of <Control> to specify accelerators that adapt to platform conventions.

    In GTK 4, the meaning of modifiers has been fixed, and backends are expected to map the platform conventions to the existing modifiers. The expected use of modifiers in GTK 4 is:

    GDK_CONTROL_MASK Primary accelerators
    GDK_ALT_MASK Mnemonics
    GDK_SHIFT_MASK Extending selections
    GDK_CONTROL_MASK Modifying selections
    GDK_CONTROL_MASK|GDK_ALT_MASK Prevent text input
  • Adapt to drawing model changes

    This area has seen the most radical changes in the transition from GTK 3 to GTK 4. Widgets no longer use a draw() function to render their contents to a cairo surface. Instead, they have a snapshot() function that creates one or more GskRenderNodes to represent their content. Third-party widgets that use a draw() function or a “draw” signal handler for custom drawing will need to be converted to use gtk_snapshot_append_cairo().

    The auxiliary GtkSnapshot object has APIs to help with creating render nodes.

    If you are using a GtkDrawingArea for custom drawing, you need to switch to using gtk_drawing_area_set_draw_func() to set a draw function instead of connecting a handler to the “draw” signal.

  • Invalidation handling has changed

    Only gtk_widget_queue_draw() is left to mark a widget as needing redraw. Variations like gtk_widget_queue_draw_rectangle() or gtk_widget_queue_draw_region() are no longer available.

  • Stop using GtkWidget::draw

    The “draw” signal has been removed. Widgets need to implement the GtkWidgetClass.snapshot() function now. Connecting draw signal handlers is no longer possible. If you want to keep using cairo for drawing, use gtk_snaphot_append_cairo().

  • Widgets are now visible by default

    The default value of “visible” in GTK 4 is TRUE, so you no longer need to explicitly show all your widgets. On the flip side, you need to hide widgets that are not meant to be visible from the start. The only widgets that still need to be explicitly shown are toplevel windows, dialogs and popovers.

    A convenient way to remove unnecessary property assignments like this from ui files it run the command gtk4-builder-tool simplify --replace on them.

    The function gtk_widget_show_all(), the “no-show-all” property and its getter and setter have been removed in GTK 4, so you should stop using them.

  • GdkPixbuf is deemphasized

    A number of GdkPixbuf-based APIs have been removed. The available replacements are either using GIcon, or the newly introduced GdkTexture or GdkPaintable classes instead. If you are dealing with pixbufs, you can use gdk_texture_new_for_pixbuf() to convert them to texture objects where needed.

  • GtkWidget event signals are removed

    Event controllers and GtkGestures have already been introduced in GTK 3 to handle input for many cases. In GTK 4, the traditional widget signals for handling input, such as “motion-event” or “event” have been removed. All event handling is done via event controllers now.

  • Window content observation has changed

    Observing widget contents and widget size is now done by using the GtkWidgetPaintable object instead of connecting to widget signals.

  • Monitor handling has changed

    Instead of a monitor number, GdkMonitor is now used throughout. gdk_display_get_monitors() returns the list of monitors that can be queried or observed for monitors to pass to APIs like gtk_window_fullscreen_on_monitor().

    Gdk.Monitor.get_primary() was removed but we can likely detect the laptop screen with Gdk.Monitor.get_connector, either if a laptop screen is reported as a separate connector or copying parsing logic from e.g. libkscreen

  • Adapt to cursor API changes

    Use the new gtk_widget_set_cursor() function to set cursors, instead of setting the cursor on the underlying window directly. This is necessary because most widgets don’t have their own window anymore, turning any such calls into global cursor changes.

    For creating standard cursors, gdk_cursor_new_for_display() has been removed, you have to use cursor names instead of GdkCursorType. For creating custom cursors, use gdk_cursor_new_from_texture(). The ability to get cursor images has been removed.

  • Adapt to icon size API changes

    Instead of the existing extensible set of symbolic icon sizes, GTK now only supports normal and large icons with the GtkIconSize enumeration. The actual sizes can be defined by themes via the CSS property -gtk-icon-size.

    GtkImage setters like gtk_image_set_from_icon_name() no longer take a GtkIconSize argument. You can use the separate gtk_image_set_icon_size() setter if you need to override the icon size.

    The :stock-size property of GtkCellRendererPixbuf has been renamed to “icon-size”.

  • Adapt to changes in the API of GtkEntry, GtkSearchEntry and GtkSpinButton

    The GtkEditable interface has been made more useful, and the core functionality of GtkEntry has been broken out as a GtkText widget. GtkEntry, GtkSearchEntry, GtkSpinButton and the new GtkPasswordEntry now use a GtkText widget internally and implement GtkEditable. In particular, this means that it is no longer possible to use GtkEntry API such as gtk_entry_grab_focus_without_selecting() on a search entry.

    Use GtkEditable API for editable functionality, and widget-specific APIs for things that go beyond the common interface. For password entries, use GtkPasswordEntry. As an example, gtk_spin_button_set_max_width_chars() has been removed in favor of gtk_editable_set_max_width_chars().

  • Adapt to changes in GtkOverlay API

    The GtkOverlay :pass-through child property has been replaced by the “can-target” property. Note that they have the opposite sense: pass-through == !can-target.

  • Adapt to GtkScale changes

    The default value of “draw-value” has been changed to FALSE. If you want your scales to draw values, you will have to set this property explicitly now.

    gtk4-builder-tool can help with this conversion, with the –3to4 option of the simplify command.

  • gtk_widget_is_toplevel has been removed

    gtk_widget_is_toplevel() has been removed. Use GTK_IS_ROOT, GTK_IS_NATIVE or GTK_IS_WINDOW instead, as appropriate.

  • GtkMenu, GtkMenuBar and GtkMenuItem are gone

    These widgets were heavily relying on X11-centric concepts such as override-redirect windows and grabs, and were hard to adjust to other windowing systems.

    Menus can already be replaced using GtkPopoverMenu in GTK 3. Additionally, GTK 4 introduces GtkPopoverMenuBar to replace menubars. These new widgets can only be constructed from menu models, so the porting effort involves switching to menu models and actions.

    Tabular menus were rarely used and complicated the menu code, so they have not been brought over to GtkPopoverMenu. If you need complex layout in menu-like popups, consider directly using a GtkPopover instead.

    Since menus are gone, GtkMenuButton also lost its ability to show menus, and needs to be used with popovers in GTK 4.

  • GtkToolbar has been removed

    Toolbars were using outdated concepts such as requiring special toolitem widgets. Toolbars should be replaced by using a GtkBox with regular widgets instead and the “toolbar” style class.

  • GtkAspectFrame is no longer a frame

    GtkAspectFrame is no longer derived from GtkFrame and does not place a label and frame around its child anymore. It still lets you control the aspect ratio of its child.

  • Switch to the new Drag-and-Drop api

    The source-side Drag-and-Drop apis in GTK 4 have been changed to use an event controller, GtkDragSource. Instead of calling gtk_drag_source_set() and connecting to GtkWidget signals, you create a GtkDragSource object, attach it to the widget with gtk_widget_add_controller(), and connect to GtkDragSource signals. Instead of calling gtk_drag_begin() on a widget to start a drag manually, call gdk_drag_begin(). The ::drag-data-get signal has been replaced by the “prepare” signal, which returns a GdkContentProvider for the drag operation.

    The destination-side Drag-and-Drop API in GTK 4 have also been changed to use an event controller, GtkDropTarget. Instead of calling gtk_drag_dest_set() and connecting to GtkWidget signals, you create a GtkDropTarget object, attach it to the widget with gtk_widget_add_controller(), and connect to GtkDropTarget signals. The ::drag-motion signal has been renamed to “accept”, and instead of ::drag-data-received, you need to use async read methods on the GdkDrop object, such as gdk_drop_read_async() or gdk_drop_read_value_async().

  • Adapt to GtkIconTheme API changes

    gtk_icon_theme_lookup_icon() returns a GtkIconPaintable object now, instead of a GtkIconInfo. It always returns a paintable in the requested size, and never fails. A number of no-longer-relevant lookup flags and API variants have been removed.

    Note that while GTK 4 is moving towards GdkPaintable as a primary API for paintable content, it is meant to be a “pure” content producer, therefore a GtkIconPaintable for a symbolic icon will not get recolored depending on the context it is rendered it. To properly render a symbolic icon that is provided in the form of a GtkIconPaintable (this can be checked with gtk_icon_paintable_is_symbolic()), you have to call gtk_icon_paintable_get_icon_name() and set the icon name on a GtkImage.

  • Update to GtkFileChooser API changes

    GtkFileChooser moved to a GFile-based API. If you need to convert a path or a URI, use g_file_new_for_path(), g_file_new_for_commandline_arg(), or g_file_new_for_uri(); similarly, if you need to get a path, name or URI from a GFile, use g_file_get_path(), g_file_get_basename() or g_file_get_uri(). With the removal or path and URI-based functions, the “local-only” property has been removed; GFile can be used to access non-local as well as local resources.

    The GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER action has been removed. Use GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, instead. If a new folder is needed, the user can create one.

    The “confirm-overwrite” signal, and the “do-overwrite-confirmation” property have been removed from GtkFileChooser. The file chooser widgets will automatically handle the confirmation of overwriting a file when using GTK_FILE_CHOOSER_ACTION_SAVE.

    GtkFileChooser does not support a custom extra widget any more. If you need to add extra widgets, use gtk_file_chooser_add_choice() instead.

    GtkFileChooser does not support a custom preview widget any more. If you need to show a custom preview, you can create your own GtkDialog with a GtkFileChooserWidget and your own preview widget that you update whenever the “selection-changed” signal is emitted.

  • Stop using blocking dialog functions

    GtkDialog, GtkNativeDialog, and GtkPrintOperation removed their blocking API using nested main loops. Nested main loops present re-entrancy issues and other hard to debug issues when coupled with other event sources (IPC, accessibility, network operations) that are not under the toolkit or the application developer’s control. Additionally, “stop-the-world” functions do not fit the event-driven programming model of GTK.

    You can replace calls to gtk_dialog_run() by specifying that the GtkDialog must be modal using gtk_window_set_modal() or the GTK_DIALOG_MODAL flag, and connecting to the “response” signal.

  • Stop using GtkBuildable API

    All the GtkBuildable API was made private, except for the getter function to retrieve the buildable ID. If you are using gtk_buildable_get_name() you should replace it with gtk_buildable_get_buildable_id().

  • Adapt to GtkAboutDialog API changes

    GtkAboutDialog now directly derives from GtkWindow, the GtkDialog API can no longer be used on it.

  • Adapt to GtkTreeView and GtkIconView tooltip context changes

    The getter functions for retrieving the data from GtkTreeView and GtkIconView inside a “query-tooltip” signal do not take the pointer coordinates as inout arguments any more, but as normal in ones.

    See: gtk_tree_view_get_tooltip_context(), gtk_icon_view_get_tooltip_context()

  • Stop using GtkFileChooserButton

    The GtkFileChooserButton widget was removed, due to its shortcomings in the user interaction. You can replace it with a simple GtkButton that shows a GtkFileChooserNative dialog when clicked; once the file selection has completed, you can update the label of the GtkButton with the selected file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant