1/*
2 * Copyright © 2020 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Matthias Clasen <mclasen@redhat.com>
18 */
19
20#include "config.h"
21
22#include "gdktoplevelprivate.h"
23
24#include "gdkdisplay.h"
25#include "gdkenumtypes.h"
26#include "gdkintl.h"
27
28#include <graphene-gobject.h>
29#include <math.h>
30
31/**
32 * GdkToplevel:
33 *
34 * A `GdkToplevel` is a freestanding toplevel surface.
35 *
36 * The `GdkToplevel` interface provides useful APIs for interacting with
37 * the windowing system, such as controlling maximization and size of the
38 * surface, setting icons and transient parents for dialogs.
39 */
40
41G_DEFINE_INTERFACE (GdkToplevel, gdk_toplevel, GDK_TYPE_SURFACE)
42
43enum
44{
45 COMPUTE_SIZE,
46
47 N_SIGNALS
48};
49
50static guint signals[N_SIGNALS] = { 0 };
51
52static void
53gdk_toplevel_default_present (GdkToplevel *toplevel,
54 GdkToplevelLayout *layout)
55{
56}
57
58static gboolean
59gdk_toplevel_default_minimize (GdkToplevel *toplevel)
60{
61 return FALSE;
62}
63
64static gboolean
65gdk_toplevel_default_lower (GdkToplevel *toplevel)
66{
67 return FALSE;
68}
69
70static void
71gdk_toplevel_default_focus (GdkToplevel *toplevel,
72 guint32 timestamp)
73{
74}
75
76static gboolean
77gdk_toplevel_default_show_window_menu (GdkToplevel *toplevel,
78 GdkEvent *event)
79{
80 return FALSE;
81}
82
83static gboolean
84gdk_toplevel_default_titlebar_gesture (GdkToplevel *toplevel,
85 GdkTitlebarGesture gesture)
86{
87 return FALSE;
88}
89
90static gboolean
91gdk_toplevel_default_supports_edge_constraints (GdkToplevel *toplevel)
92{
93 return FALSE;
94}
95
96static void
97gdk_toplevel_default_inhibit_system_shortcuts (GdkToplevel *toplevel,
98 GdkEvent *event)
99{
100}
101
102static void
103gdk_toplevel_default_restore_system_shortcuts (GdkToplevel *toplevel)
104{
105}
106
107void
108gdk_toplevel_notify_compute_size (GdkToplevel *toplevel,
109 GdkToplevelSize *size)
110{
111 g_signal_emit (instance: toplevel, signal_id: signals[COMPUTE_SIZE], detail: 0, size);
112 gdk_toplevel_size_validate (size);
113}
114
115static void
116gdk_toplevel_default_init (GdkToplevelInterface *iface)
117{
118 iface->present = gdk_toplevel_default_present;
119 iface->minimize = gdk_toplevel_default_minimize;
120 iface->lower = gdk_toplevel_default_lower;
121 iface->focus = gdk_toplevel_default_focus;
122 iface->show_window_menu = gdk_toplevel_default_show_window_menu;
123 iface->supports_edge_constraints = gdk_toplevel_default_supports_edge_constraints;
124 iface->inhibit_system_shortcuts = gdk_toplevel_default_inhibit_system_shortcuts;
125 iface->restore_system_shortcuts = gdk_toplevel_default_restore_system_shortcuts;
126 iface->titlebar_gesture = gdk_toplevel_default_titlebar_gesture;
127
128 /**
129 * GdkToplevel:state: (attributes org.gtk.Property.get=gdk_toplevel_get_state)
130 *
131 * The state of the toplevel.
132 */
133 g_object_interface_install_property (g_iface: iface,
134 pspec: g_param_spec_flags (name: "state",
135 P_("State"),
136 P_("State"),
137 flags_type: GDK_TYPE_TOPLEVEL_STATE, default_value: 0,
138 flags: G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
139
140 /**
141 * GdkToplevel:title: (attributes org.gtk.Property.set=gdk_toplevel_set_title)
142 *
143 * The title of the surface.
144 */
145 g_object_interface_install_property (g_iface: iface,
146 pspec: g_param_spec_string (name: "title",
147 nick: "Title",
148 blurb: "The title of the surface",
149 NULL,
150 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
151
152 /**
153 * GdkToplevel:startup-id: (attributes org.gtk.Property.set=gdk_toplevel_set_startup_id)
154 *
155 * The startup ID of the surface.
156 *
157 * See [class@Gdk.AppLaunchContext] for more information about
158 * startup feedback.
159 */
160 g_object_interface_install_property (g_iface: iface,
161 pspec: g_param_spec_string (name: "startup-id",
162 nick: "Startup ID",
163 blurb: "The startup ID of the surface",
164 NULL,
165 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
166
167 /**
168 * GdkToplevel:transient-for: (attributes org.gtk.Property.set=gdk_toplevel_set_transient_for)
169 *
170 * The transient parent of the surface.
171 */
172 g_object_interface_install_property (g_iface: iface,
173 pspec: g_param_spec_object (name: "transient-for",
174 nick: "Transient For",
175 blurb: "The transient parent of the surface",
176 GDK_TYPE_SURFACE,
177 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
178
179 /**
180 * GdkToplevel:modal: (attributes org.gtk.Property.set=gdk_toplevel_set_modal)
181 *
182 * Whether the surface is modal.
183 */
184 g_object_interface_install_property (g_iface: iface,
185 pspec: g_param_spec_boolean (name: "modal",
186 nick: "Modal",
187 blurb: "Whether the surface is modal",
188 FALSE,
189 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
190
191 /**
192 * GdkToplevel:icon-list: (attributes org.gtk.Property.set=gdk_toplevel_set_icon_list)
193 *
194 * A list of textures to use as icon.
195 */
196 g_object_interface_install_property (g_iface: iface,
197 pspec: g_param_spec_pointer (name: "icon-list",
198 nick: "Icon List",
199 blurb: "The list of icon textures",
200 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
201
202 /**
203 * GdkToplevel:decorated: (attributes org.gtk.Property.set=gdk_toplevel_set_decorated)
204 *
205 * Whether the window manager should add decorations.
206 */
207 g_object_interface_install_property (g_iface: iface,
208 pspec: g_param_spec_boolean (name: "decorated",
209 nick: "Decorated",
210 blurb: "Decorated",
211 FALSE,
212 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
213
214 /**
215 * GdkToplevel:deletable: (attributes org.gtk.Property.set=gdk_toplevel_set_deletable)
216 *
217 * Whether the window manager should allow to close the surface.
218 */
219 g_object_interface_install_property (g_iface: iface,
220 pspec: g_param_spec_boolean (name: "deletable",
221 nick: "Deletable",
222 blurb: "Deletable",
223 FALSE,
224 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
225
226 /**
227 * GdkToplevel:fullscreen-mode:
228 *
229 * The fullscreen mode of the surface.
230 */
231 g_object_interface_install_property (g_iface: iface,
232 pspec: g_param_spec_enum (name: "fullscreen-mode",
233 nick: "Fullscreen mode",
234 blurb: "Fullscreen mode",
235 enum_type: GDK_TYPE_FULLSCREEN_MODE,
236 default_value: GDK_FULLSCREEN_ON_CURRENT_MONITOR,
237 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
238
239 /**
240 * GdkToplevel:shortcuts-inhibited:
241 *
242 * Whether the surface should inhibit keyboard shortcuts.
243 */
244 g_object_interface_install_property (g_iface: iface,
245 pspec: g_param_spec_boolean (name: "shortcuts-inhibited",
246 nick: "Shortcuts inhibited",
247 blurb: "Whether keyboard shortcuts are inhibited",
248 FALSE,
249 flags: G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY));
250
251 /**
252 * GdkToplevel::compute-size:
253 * @toplevel: a `GdkToplevel`
254 * @size: (type Gdk.ToplevelSize) (out caller-allocates): a `GdkToplevelSize`
255 *
256 * Emitted when the size for the surface needs to be computed, when
257 * it is present.
258 *
259 * It will normally be emitted during or after [method@Gdk.Toplevel.present],
260 * depending on the configuration received by the windowing system.
261 * It may also be emitted at any other point in time, in response
262 * to the windowing system spontaneously changing the configuration.
263 *
264 * It is the responsibility of the toplevel user to handle this signal
265 * and compute the desired size of the toplevel, given the information
266 * passed via the [struct@Gdk.ToplevelSize] object. Failing to do so
267 * will result in an arbitrary size being used as a result.
268 */
269 signals[COMPUTE_SIZE] =
270 g_signal_new (signal_name: "compute-size",
271 GDK_TYPE_TOPLEVEL,
272 signal_flags: G_SIGNAL_RUN_LAST,
273 class_offset: 0,
274 NULL, NULL,
275 NULL,
276 G_TYPE_NONE, n_params: 1,
277 GDK_TYPE_TOPLEVEL_SIZE | G_SIGNAL_TYPE_STATIC_SCOPE);
278}
279
280guint
281gdk_toplevel_install_properties (GObjectClass *object_class,
282 guint first_prop)
283{
284 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_STATE, name: "state");
285 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_TITLE, name: "title");
286 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_STARTUP_ID, name: "startup-id");
287 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_TRANSIENT_FOR, name: "transient-for");
288 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_MODAL, name: "modal");
289 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_ICON_LIST, name: "icon-list");
290 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_DECORATED, name: "decorated");
291 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_DELETABLE, name: "deletable");
292 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE, name: "fullscreen-mode");
293 g_object_class_override_property (oclass: object_class, property_id: first_prop + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED, name: "shortcuts-inhibited");
294
295 return GDK_TOPLEVEL_NUM_PROPERTIES;
296}
297
298/**
299 * gdk_toplevel_present:
300 * @toplevel: the `GdkToplevel` to show
301 * @layout: the `GdkToplevelLayout` object used to layout
302 *
303 * Present @toplevel after having processed the `GdkToplevelLayout` rules.
304 *
305 * If the toplevel was previously not showing, it will be showed,
306 * otherwise it will change layout according to @layout.
307 *
308 * GDK may emit the [signal@Gdk.Toplevel::compute-size] signal to let
309 * the user of this toplevel compute the preferred size of the toplevel
310 * surface.
311 *
312 * Presenting is asynchronous and the specified layout parameters are not
313 * guaranteed to be respected.
314 */
315void
316gdk_toplevel_present (GdkToplevel *toplevel,
317 GdkToplevelLayout *layout)
318{
319 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
320 g_return_if_fail (layout != NULL);
321
322 GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->present (toplevel, layout);
323}
324
325/**
326 * gdk_toplevel_minimize:
327 * @toplevel: a `GdkToplevel`
328 *
329 * Asks to minimize the @toplevel.
330 *
331 * The windowing system may choose to ignore the request.
332 *
333 * Returns: %TRUE if the surface was minimized
334 */
335gboolean
336gdk_toplevel_minimize (GdkToplevel *toplevel)
337{
338 g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
339
340 return GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->minimize (toplevel);
341}
342
343/**
344 * gdk_toplevel_lower:
345 * @toplevel: a `GdkToplevel`
346 *
347 * Asks to lower the @toplevel below other windows.
348 *
349 * The windowing system may choose to ignore the request.
350 *
351 * Returns: %TRUE if the surface was lowered
352 */
353gboolean
354gdk_toplevel_lower (GdkToplevel *toplevel)
355{
356 g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
357
358 return GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->lower (toplevel);
359}
360
361/**
362 * gdk_toplevel_focus:
363 * @toplevel: a `GdkToplevel`
364 * @timestamp: timestamp of the event triggering the surface focus
365 *
366 * Sets keyboard focus to @surface.
367 *
368 * In most cases, [method@Gtk.Window.present_with_time] should be
369 * used on a [class@Gtk.Window], rather than calling this function.
370 */
371void
372gdk_toplevel_focus (GdkToplevel *toplevel,
373 guint32 timestamp)
374{
375 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
376
377 GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->focus (toplevel, timestamp);
378}
379
380/**
381 * gdk_toplevel_get_state: (attributes org.gtk.Method.get_property=state)
382 * @toplevel: a `GdkToplevel`
383 *
384 * Gets the bitwise or of the currently active surface state flags,
385 * from the `GdkToplevelState` enumeration.
386 *
387 * Returns: surface state bitfield
388 */
389GdkToplevelState
390gdk_toplevel_get_state (GdkToplevel *toplevel)
391{
392 GdkToplevelState state;
393
394 g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), 0);
395
396 g_object_get (object: toplevel, first_property_name: "state", &state, NULL);
397
398 return state;
399}
400
401/**
402 * gdk_toplevel_set_title: (attributes org.gtk.Method.set_property=title)
403 * @toplevel: a `GdkToplevel`
404 * @title: title of @surface
405 *
406 * Sets the title of a toplevel surface.
407 *
408 * The title maybe be displayed in the titlebar,
409 * in lists of windows, etc.
410 */
411void
412gdk_toplevel_set_title (GdkToplevel *toplevel,
413 const char *title)
414{
415 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
416
417 g_object_set (object: toplevel, first_property_name: "title", title, NULL);
418}
419
420/**
421 * gdk_toplevel_set_startup_id: (attributes org.gtk.Method.set_property=startup-id)
422 * @toplevel: a `GdkToplevel`
423 * @startup_id: a string with startup-notification identifier
424 *
425 * Sets the startup notification ID.
426 *
427 * When using GTK, typically you should use
428 * [method@Gtk.Window.set_startup_id] instead of this
429 * low-level function.
430 */
431void
432gdk_toplevel_set_startup_id (GdkToplevel *toplevel,
433 const char *startup_id)
434{
435 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
436
437 g_object_set (object: toplevel, first_property_name: "startup-id", startup_id, NULL);
438}
439
440/**
441 * gdk_toplevel_set_transient_for: (attributes org.gtk.Method.set_property=transient-for)
442 * @toplevel: a `GdkToplevel`
443 * @parent: another toplevel `GdkSurface`
444 *
445 * Sets a transient-for parent.
446 *
447 * Indicates to the window manager that @surface is a transient
448 * dialog associated with the application surface @parent. This
449 * allows the window manager to do things like center @surface
450 * on @parent and keep @surface above @parent.
451 *
452 * See [method@Gtk.Window.set_transient_for] if you’re using
453 * [class@Gtk.Window] or [class@Gtk.Dialog].
454 */
455void
456gdk_toplevel_set_transient_for (GdkToplevel *toplevel,
457 GdkSurface *parent)
458{
459 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
460
461 g_object_set (object: toplevel, first_property_name: "transient-for", parent, NULL);
462}
463
464/**
465 * gdk_toplevel_set_modal: (attributes org.gtk.Method.set_property=modal)
466 * @toplevel: a `GdkToplevel`
467 * @modal: %TRUE if the surface is modal, %FALSE otherwise.
468 *
469 * Sets the toplevel to be modal.
470 *
471 * The application can use this hint to tell the
472 * window manager that a certain surface has modal
473 * behaviour. The window manager can use this information
474 * to handle modal surfaces in a special way.
475 *
476 * You should only use this on surfaces for which you have
477 * previously called [method@Gdk.Toplevel.set_transient_for].
478 */
479void
480gdk_toplevel_set_modal (GdkToplevel *toplevel,
481 gboolean modal)
482{
483 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
484
485 g_object_set (object: toplevel, first_property_name: "modal", modal, NULL);
486}
487
488/**
489 * gdk_toplevel_set_icon_list: (attributes org.gtk.Method.set_property=icon-list)
490 * @toplevel: a `GdkToplevel`
491 * @surfaces: (transfer none) (element-type GdkTexture):
492 * A list of textures to use as icon, of different sizes
493 *
494 * Sets a list of icons for the surface.
495 *
496 * One of these will be used to represent the surface in iconic form.
497 * The icon may be shown in window lists or task bars. Which icon
498 * size is shown depends on the window manager. The window manager
499 * can scale the icon but setting several size icons can give better
500 * image quality.
501 *
502 * Note that some platforms don't support surface icons.
503 */
504void
505gdk_toplevel_set_icon_list (GdkToplevel *toplevel,
506 GList *surfaces)
507{
508 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
509
510 g_object_set (object: toplevel, first_property_name: "icon-list", surfaces, NULL);
511}
512
513/**
514 * gdk_toplevel_show_window_menu:
515 * @toplevel: a `GdkToplevel`
516 * @event: a `GdkEvent` to show the menu for
517 *
518 * Asks the windowing system to show the window menu.
519 *
520 * The window menu is the menu shown when right-clicking the titlebar
521 * on traditional windows managed by the window manager. This is useful
522 * for windows using client-side decorations, activating it with a
523 * right-click on the window decorations.
524 *
525 * Returns: %TRUE if the window menu was shown and %FALSE otherwise.
526 */
527gboolean
528gdk_toplevel_show_window_menu (GdkToplevel *toplevel,
529 GdkEvent *event)
530{
531 g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
532
533 return GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->show_window_menu (toplevel, event);
534}
535
536/**
537 * gdk_toplevel_set_decorated: (attributes org.gtk.Method.set_property=decorated)
538 * @toplevel: a `GdkToplevel`
539 * @decorated: %TRUE to request decorations
540 *
541 * Sets the toplevel to be decorated.
542 *
543 * Setting @decorated to %FALSE hints the desktop environment
544 * that the surface has its own, client-side decorations and
545 * does not need to have window decorations added.
546 */
547void
548gdk_toplevel_set_decorated (GdkToplevel *toplevel,
549 gboolean decorated)
550{
551 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
552
553 g_object_set (object: toplevel, first_property_name: "decorated", decorated, NULL);
554}
555
556/**
557 * gdk_toplevel_set_deletable: (attributes org.gtk.Method.set_property=deletable)
558 * @toplevel: a `GdkToplevel`
559 * @deletable: %TRUE to request a delete button
560 *
561 * Sets the toplevel to be deletable.
562 *
563 * Setting @deletable to %TRUE hints the desktop environment
564 * that it should offer the user a way to close the surface.
565 */
566void
567gdk_toplevel_set_deletable (GdkToplevel *toplevel,
568 gboolean deletable)
569{
570 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
571
572 g_object_set (object: toplevel, first_property_name: "deletable", deletable, NULL);
573}
574
575/**
576 * gdk_toplevel_supports_edge_constraints:
577 * @toplevel: a `GdkToplevel`
578 *
579 * Returns whether the desktop environment supports
580 * tiled window states.
581 *
582 * Returns: %TRUE if the desktop environment supports tiled window states
583 */
584gboolean
585gdk_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
586{
587 g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
588
589 return GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->supports_edge_constraints (toplevel);
590}
591
592/**
593 * gdk_toplevel_inhibit_system_shortcuts:
594 * @toplevel: a `GdkToplevel`
595 * @event: (nullable): the `GdkEvent` that is triggering the inhibit
596 * request, or %NULL if none is available
597 *
598 * Requests that the @toplevel inhibit the system shortcuts.
599 *
600 * This is asking the desktop environment/windowing system to let all
601 * keyboard events reach the surface, as long as it is focused, instead
602 * of triggering system actions.
603 *
604 * If granted, the rerouting remains active until the default shortcuts
605 * processing is restored with [method@Gdk.Toplevel.restore_system_shortcuts],
606 * or the request is revoked by the desktop environment, windowing system
607 * or the user.
608 *
609 * A typical use case for this API is remote desktop or virtual machine
610 * viewers which need to inhibit the default system keyboard shortcuts
611 * so that the remote session or virtual host gets those instead of the
612 * local environment.
613 *
614 * The windowing system or desktop environment may ask the user to grant
615 * or deny the request or even choose to ignore the request entirely.
616 *
617 * The caller can be notified whenever the request is granted or revoked
618 * by listening to the [property@Gdk.Toplevel:shortcuts-inhibited] property.
619 */
620void
621gdk_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
622 GdkEvent *event)
623{
624 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
625
626 GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->inhibit_system_shortcuts (toplevel,
627 event);
628}
629
630/**
631 * gdk_toplevel_restore_system_shortcuts:
632 * @toplevel: a `GdkToplevel`
633 *
634 * Restore default system keyboard shortcuts which were previously
635 * inhibited.
636 *
637 * This undoes the effect of [method@Gdk.Toplevel.inhibit_system_shortcuts].
638 */
639void
640gdk_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
641{
642 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
643
644 GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->restore_system_shortcuts (toplevel);
645}
646
647/**
648 * gdk_toplevel_begin_resize:
649 * @toplevel: a `GdkToplevel`
650 * @edge: the edge or corner from which the drag is started
651 * @device: (nullable): the device used for the operation
652 * @button: the button being used to drag, or 0 for a keyboard-initiated drag
653 * @x: surface X coordinate of mouse click that began the drag
654 * @y: surface Y coordinate of mouse click that began the drag
655 * @timestamp: timestamp of mouse click that began the drag (use
656 * [method@Gdk.Event.get_time])
657 *
658 * Begins an interactive resize operation.
659 *
660 * You might use this function to implement a “window resize grip.”
661 */
662void
663gdk_toplevel_begin_resize (GdkToplevel *toplevel,
664 GdkSurfaceEdge edge,
665 GdkDevice *device,
666 int button,
667 double x,
668 double y,
669 guint32 timestamp)
670{
671 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
672
673 if (device == NULL)
674 {
675 GdkSeat *seat = gdk_display_get_default_seat (display: gdk_surface_get_display (GDK_SURFACE (toplevel)));
676 if (button == 0)
677 device = gdk_seat_get_keyboard (seat);
678 else
679 device = gdk_seat_get_pointer (seat);
680 }
681
682 GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->begin_resize (toplevel,
683 edge,
684 device,
685 button,
686 x, y,
687 timestamp);
688}
689
690/**
691 * gdk_toplevel_begin_move:
692 * @toplevel: a `GdkToplevel`
693 * @device: the device used for the operation
694 * @button: the button being used to drag, or 0 for a keyboard-initiated drag
695 * @x: surface X coordinate of mouse click that began the drag
696 * @y: surface Y coordinate of mouse click that began the drag
697 * @timestamp: timestamp of mouse click that began the drag (use
698 * [method@Gdk.Event.get_time])
699 *
700 * Begins an interactive move operation.
701 *
702 * You might use this function to implement draggable titlebars.
703 */
704void
705gdk_toplevel_begin_move (GdkToplevel *toplevel,
706 GdkDevice *device,
707 int button,
708 double x,
709 double y,
710 guint32 timestamp)
711{
712 g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
713
714 if (device == NULL)
715 {
716 GdkSeat *seat = gdk_display_get_default_seat (display: gdk_surface_get_display (GDK_SURFACE (toplevel)));
717 if (button == 0)
718 device = gdk_seat_get_keyboard (seat);
719 else
720 device = gdk_seat_get_pointer (seat);
721 }
722
723 GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->begin_move (toplevel,
724 device,
725 button,
726 x, y,
727 timestamp);
728}
729
730/**
731 * gdk_toplevel_titlebar_gesture:
732 * @toplevel: a `GdkToplevel`
733 * @gesture: a `GdkTitlebarGesture`
734 *
735 * Since: 4.4
736 */
737gboolean
738gdk_toplevel_titlebar_gesture (GdkToplevel *toplevel,
739 GdkTitlebarGesture gesture)
740{
741 g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
742
743 return GDK_TOPLEVEL_GET_IFACE (ptr: toplevel)->titlebar_gesture (toplevel,
744 gesture);
745}
746

source code of gtk/gdk/gdktoplevel.c