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 | |
41 | G_DEFINE_INTERFACE (GdkToplevel, gdk_toplevel, GDK_TYPE_SURFACE) |
42 | |
43 | enum |
44 | { |
45 | COMPUTE_SIZE, |
46 | |
47 | N_SIGNALS |
48 | }; |
49 | |
50 | static guint signals[N_SIGNALS] = { 0 }; |
51 | |
52 | static void |
53 | gdk_toplevel_default_present (GdkToplevel *toplevel, |
54 | GdkToplevelLayout *layout) |
55 | { |
56 | } |
57 | |
58 | static gboolean |
59 | gdk_toplevel_default_minimize (GdkToplevel *toplevel) |
60 | { |
61 | return FALSE; |
62 | } |
63 | |
64 | static gboolean |
65 | gdk_toplevel_default_lower (GdkToplevel *toplevel) |
66 | { |
67 | return FALSE; |
68 | } |
69 | |
70 | static void |
71 | gdk_toplevel_default_focus (GdkToplevel *toplevel, |
72 | guint32 timestamp) |
73 | { |
74 | } |
75 | |
76 | static gboolean |
77 | (GdkToplevel *toplevel, |
78 | GdkEvent *event) |
79 | { |
80 | return FALSE; |
81 | } |
82 | |
83 | static gboolean |
84 | gdk_toplevel_default_titlebar_gesture (GdkToplevel *toplevel, |
85 | GdkTitlebarGesture gesture) |
86 | { |
87 | return FALSE; |
88 | } |
89 | |
90 | static gboolean |
91 | gdk_toplevel_default_supports_edge_constraints (GdkToplevel *toplevel) |
92 | { |
93 | return FALSE; |
94 | } |
95 | |
96 | static void |
97 | gdk_toplevel_default_inhibit_system_shortcuts (GdkToplevel *toplevel, |
98 | GdkEvent *event) |
99 | { |
100 | } |
101 | |
102 | static void |
103 | gdk_toplevel_default_restore_system_shortcuts (GdkToplevel *toplevel) |
104 | { |
105 | } |
106 | |
107 | void |
108 | gdk_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 | |
115 | static void |
116 | gdk_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 | |
280 | guint |
281 | gdk_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 | */ |
315 | void |
316 | gdk_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 | */ |
335 | gboolean |
336 | gdk_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 | */ |
353 | gboolean |
354 | gdk_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 | */ |
371 | void |
372 | gdk_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 | */ |
389 | GdkToplevelState |
390 | gdk_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 | */ |
411 | void |
412 | gdk_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 | */ |
431 | void |
432 | gdk_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 | */ |
455 | void |
456 | gdk_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 | */ |
479 | void |
480 | gdk_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 | */ |
504 | void |
505 | gdk_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 | */ |
527 | gboolean |
528 | (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 | */ |
547 | void |
548 | gdk_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 | */ |
566 | void |
567 | gdk_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 | */ |
584 | gboolean |
585 | gdk_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 | */ |
620 | void |
621 | gdk_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 | */ |
639 | void |
640 | gdk_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 | */ |
662 | void |
663 | gdk_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 | */ |
704 | void |
705 | gdk_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 | */ |
737 | gboolean |
738 | gdk_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 | |