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.
[x] 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 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.
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.
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.
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.
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.
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.
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.
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
[ ] Stop using GtkWidget event signals
[ ] Stop using GtkBox padding, fill and expand child properties
[ ] Reduce the use of generic container APIs
[x] Set a proper application ID
To do on transition
[ ] Subclassing
[ ] Adapt to GdkWindow API changes
[ ] Life-cycle handling
[ ] Stop using GdkScreen
[ ] The “iconified” window state has been renamed to “minimized”
[ ] Adapt to GdkEvent API changes
[ ] Stop using grabs
[ ] Adapt to coordinate API changes
[ ] Adapt to changes in keyboard modifier handling
[ ] Adapt to drawing model changes
[ ] Invalidation handling has changed
[ ] Stop using GtkWidget::draw
[ ] Widgets are now visible by default
[ ] GdkPixbuf is deemphasized
[ ] GtkWidget event signals are removed
[ ] Window content observation has changed
[ ] Monitor handling has changed
Gdk.Monitor.get_primary()
was removed but we can likely detect the laptop screen withGdk.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
[ ] Adapt to icon size API changes
[ ] Adapt to changes in the API of GtkEntry, GtkSearchEntry and GtkSpinButton
[ ] Adapt to changes in GtkOverlay API
[ ] Adapt to GtkScale changes
[ ] gtk_widget_is_toplevel has been removed
[ ] GtkMenu, GtkMenuBar and GtkMenuItem are gone
[ ] GtkToolbar has been removed
[ ] GtkAspectFrame is no longer a frame
[ ] Switch to the new Drag-and-Drop api
[ ] Adapt to GtkIconTheme API changes
[ ] Update to GtkFileChooser API changes
[ ] Stop using blocking dialog functions
[ ] Stop using GtkBuildable API
[ ] Adapt to GtkAboutDialog API changes
[ ] Adapt to GtkTreeView and GtkIconView tooltip context changes
[ ] Stop using GtkFileChooserButton