![]() |
![]() |
![]() |
![]() |
This section outlines porting tasks that you need to tackle when you get to the point that you actually build your application against GTK 4. Making it possible to prepare for these in GTK 3 would have been either impossible or impractical.
Some of the larger themes of GTK 4 development are hard to cover in the form of checklist items, so we mention them separately up-front.
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.
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.
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 root window is an X11-centric concept that is no longer
exposed in the backend-neutral GDK API. If you need to interact
with the X11 root window, you can use
gdk_x11_display_get_xrootwindow()
to get its XID.
This object is not useful with current GTK drawing APIs and has been removed without replacement.
The GdkDeviceManager object has been removed in GTK 4. Most of its APIs already had replacements in GTK 3 and were deprecated in favor of GdkSeat.
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()
.
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.
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.
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.
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()
.
GdkKeymap no longer exists as an independent object.
If you need access to keymap state, it is now exposed as
properties on the GdkDevice representing the keyboard:
“direction”, “has-bidi-layouts”,
“caps-lock-state”, “num-lock-state”,
“scroll-lock-state” and “modifier-state”. To
obtain the keyboard device, you can use
gdk_seat_get_keyboard (gdk_display_get_default_seat (display)
.
If you need access to translated keys for event handling,
GdkEvent now includes all of the translated key state,
including consumed modifiers, group and shift level, so there
should be no need to manually call
gdk_keymap_translate_keyboard_state()
(which has been removed).
If you need to do forward or backward mapping between key codes
and key values, use gdk_display_map_keycode()
and
gdk_display_map_keyval()
, which are the replacements for
gdk_keymap_get_entries_for_keycode()
and
gdk_keymap_get_entries_for_keyval()
.
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 |
Consequently, GdkModifierIntent and related APIs have been
removed, and <Control>
is preferred
over <Primary>
in accelerators.
A related change is that GTK 4 no longer supports the use of
archaic X11 “real” modifiers with the names Mod1,…,
Mod5, and GDK_MOD1_MASK
has been renamed to GDK_ALT_MASK
.
The GtkClipboard
API has been removed, and
replaced by GdkClipboard. There is not direct 1:1 mapping
between the old an the new API, so it cannot be a mechanical
replacement; the new API is based on object types and GValue
like object properties, instead of opaque identifiers, so it
should be easier to use.
For instance, the example below copies the contents of an entry into the clipboard:
static void copy_text (GtkWidget *widget) { GtkEditable *editable = GTK_EDITABLE (widget); // Initialize a GValue with the contents of the widget GValue value = G_VALUE_INIT; g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, gtk_editable_get_text (editable)); // Store the value in the clipboard object GdkClipboard *clipboard = gtk_widget_get_clipboard (widget); gdk_clipboard_set_value (clipboard, &value); g_value_unset (&value); }
whereas the example below pastes the contents into the entry:
static void paste_text (GtkWidget *widget) { GtkEditable *editable = GTK_EDITABLE (widget); // Initialize a GValue to receive text GValue value = G_VALUE_INIT; g_value_init (&value, G_TYPE_STRING); // Get the content provider for the clipboard, and ask it for text GdkClipboard *clipboard = gtk_widget_get_clipboard (widget); GdkContentProvider *provider = gdk_clipboard_get_content (clipboard); // If the content provider does not contain text, we are not interested if (!gdk_content_provider_get_value (provider, &value, NULL)) return; const char *str = g_value_get_string (&value); gtk_editable_set_text (editable, str); g_value_unset (&value); }
The convenience API for specific target types in
GtkClipboard
has been replaced by their
corresponding GType:
GtkClipboard | GType |
---|---|
|
G_TYPE_STRING
|
|
GTK_TYPE_TEXT_BUFFER
|
|
GDK_TYPE_PIXBUF
|
|
GDK_TYPE_FILE_LIST
|
Note: Support for rich text serialization across different processes for GtkTextBuffer is not available any more.
If you are copying the contents of an image, it is recommended to use GDK_TYPE_PAINTABLE instead of GDK_TYPE_PIXBUF, to minimize the amount of potential copies.
The function gtk_get_current_event()
and its variants have been
replaced by equivalent event controller APIs:
gtk_event_controller_get_current_event()
, etc.
A number of the changes outlined below affect .ui files. The gtk4-builder-tool simplify command can perform many of the necessary changes automatically, when called with the –3to4 option. You should always review the resulting changes.
The <requires> tag now supports for the “lib” attribute the “gtk” value only, instead of the “gtk+” one previously.