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