1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27 #include "config.h"
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include "gdk/gdk.h"
33 #include "gdk/gdkkeysyms.h"
34
35 #include "gtkintl.h"
36
37 #include "gtkprivate.h"
38 #include "gtkrc.h"
39 #include "gtkwindow.h"
40 #include "gtkwindow-decorate.h"
41 #include "gtkbindings.h"
42 #include "gtkkeyhash.h"
43 #include "gtkmain.h"
44 #include "gtkmnemonichash.h"
45 #include "gtkmenubar.h"
46 #include "gtkiconfactory.h"
47 #include "gtkicontheme.h"
48 #include "gtkmarshalers.h"
49 #include "gtkplug.h"
50 #include "gtkbuildable.h"
51 #include "gtkalias.h"
52
53 #ifdef GDK_WINDOWING_X11
54 #include "x11/gdkx.h"
55 #endif
56
57 enum {
58 SET_FOCUS,
59 FRAME_EVENT,
60 ACTIVATE_FOCUS,
61 ACTIVATE_DEFAULT,
62 KEYS_CHANGED,
63 LAST_SIGNAL
64 };
65
66 enum {
67 PROP_0,
68
69 /* Construct */
70 PROP_TYPE,
71
72 /* Normal Props */
73 PROP_TITLE,
74 PROP_ROLE,
75 PROP_ALLOW_SHRINK,
76 PROP_ALLOW_GROW,
77 PROP_RESIZABLE,
78 PROP_MODAL,
79 PROP_WIN_POS,
80 PROP_DEFAULT_WIDTH,
81 PROP_DEFAULT_HEIGHT,
82 PROP_DESTROY_WITH_PARENT,
83 PROP_ICON,
84 PROP_ICON_NAME,
85 PROP_SCREEN,
86 PROP_TYPE_HINT,
87 PROP_SKIP_TASKBAR_HINT,
88 PROP_SKIP_PAGER_HINT,
89 PROP_URGENCY_HINT,
90 PROP_ACCEPT_FOCUS,
91 PROP_FOCUS_ON_MAP,
92 PROP_DECORATED,
93 PROP_DELETABLE,
94 PROP_GRAVITY,
95 PROP_TRANSIENT_FOR,
96 PROP_OPACITY,
97
98 /* Readonly properties */
99 PROP_IS_ACTIVE,
100 PROP_HAS_TOPLEVEL_FOCUS,
101
102 /* Writeonly properties */
103 PROP_STARTUP_ID,
104
105 PROP_MNEMONICS_VISIBLE,
106
107 LAST_ARG
108 };
109
110 typedef struct
111 {
112 GList *icon_list;
113 GdkPixmap *icon_pixmap;
114 GdkPixmap *icon_mask;
115 gchar *icon_name;
116 guint realized : 1;
117 guint using_default_icon : 1;
118 guint using_parent_icon : 1;
119 guint using_themed_icon : 1;
120 } GtkWindowIconInfo;
121
122 typedef struct {
123 GdkGeometry geometry; /* Last set of geometry hints we set */
124 GdkWindowHints flags;
125 GdkRectangle configure_request;
126 } GtkWindowLastGeometryInfo;
127
128 struct _GtkWindowGeometryInfo
129 {
130 /* Properties that the app has set on the window
131 */
132 GdkGeometry geometry; /* Geometry hints */
133 GdkWindowHints mask;
134 GtkWidget *widget; /* subwidget to which hints apply */
135 /* from last gtk_window_resize () - if > 0, indicates that
136 * we should resize to this size.
137 */
138 gint resize_width;
139 gint resize_height;
140
141 /* From last gtk_window_move () prior to mapping -
142 * only used if initial_pos_set
143 */
144 gint initial_x;
145 gint initial_y;
146
147 /* Default size - used only the FIRST time we map a window,
148 * only if > 0.
149 */
150 gint default_width;
151 gint default_height;
152 /* whether to use initial_x, initial_y */
153 guint initial_pos_set : 1;
154 /* CENTER_ALWAYS or other position constraint changed since
155 * we sent the last configure request.
156 */
157 guint position_constraints_changed : 1;
158
159 /* if true, default_width, height come from gtk_window_parse_geometry,
160 * and thus should be multiplied by the increments and affect the
161 * geometry widget only
162 */
163 guint default_is_geometry : 1;
164
165 GtkWindowLastGeometryInfo last;
166 };
167
168 #define GTK_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_WINDOW, GtkWindowPrivate))
169
170 typedef struct _GtkWindowPrivate GtkWindowPrivate;
171
172 struct _GtkWindowPrivate
173 {
174 GtkMnemonicHash *mnemonic_hash;
175
176 guint above_initially : 1;
177 guint below_initially : 1;
178 guint fullscreen_initially : 1;
179 guint skips_taskbar : 1;
180 guint skips_pager : 1;
181 guint urgent : 1;
182 guint accept_focus : 1;
183 guint focus_on_map : 1;
184 guint deletable : 1;
185 guint transient_parent_group : 1;
186
187 guint reset_type_hint : 1;
188 guint opacity_set : 1;
189 guint builder_visible : 1;
190
191 guint mnemonics_visible : 1;
192 guint mnemonics_visible_set : 1;
193
194 GdkWindowTypeHint type_hint;
195
196 gdouble opacity;
197
198 gchar *startup_id;
199 };
200
201 static void gtk_window_dispose (GObject *object);
202 static void gtk_window_destroy (GtkObject *object);
203 static void gtk_window_finalize (GObject *object);
204 static void gtk_window_show (GtkWidget *widget);
205 static void gtk_window_hide (GtkWidget *widget);
206 static void gtk_window_map (GtkWidget *widget);
207 static void gtk_window_unmap (GtkWidget *widget);
208 static void gtk_window_realize (GtkWidget *widget);
209 static void gtk_window_unrealize (GtkWidget *widget);
210 static void gtk_window_size_request (GtkWidget *widget,
211 GtkRequisition *requisition);
212 static void gtk_window_size_allocate (GtkWidget *widget,
213 GtkAllocation *allocation);
214 static gint gtk_window_event (GtkWidget *widget,
215 GdkEvent *event);
216 static gboolean gtk_window_map_event (GtkWidget *widget,
217 GdkEventAny *event);
218 static gboolean gtk_window_frame_event (GtkWindow *window,
219 GdkEvent *event);
220 static gint gtk_window_configure_event (GtkWidget *widget,
221 GdkEventConfigure *event);
222 static gint gtk_window_key_press_event (GtkWidget *widget,
223 GdkEventKey *event);
224 static gint gtk_window_key_release_event (GtkWidget *widget,
225 GdkEventKey *event);
226 static gint gtk_window_enter_notify_event (GtkWidget *widget,
227 GdkEventCrossing *event);
228 static gint gtk_window_leave_notify_event (GtkWidget *widget,
229 GdkEventCrossing *event);
230 static gint gtk_window_focus_in_event (GtkWidget *widget,
231 GdkEventFocus *event);
232 static gint gtk_window_focus_out_event (GtkWidget *widget,
233 GdkEventFocus *event);
234 static gint gtk_window_client_event (GtkWidget *widget,
235 GdkEventClient *event);
236 static void gtk_window_check_resize (GtkContainer *container);
237 static gint gtk_window_focus (GtkWidget *widget,
238 GtkDirectionType direction);
239 static void gtk_window_real_set_focus (GtkWindow *window,
240 GtkWidget *focus);
241
242 static void gtk_window_real_activate_default (GtkWindow *window);
243 static void gtk_window_real_activate_focus (GtkWindow *window);
244 static void gtk_window_move_focus (GtkWindow *window,
245 GtkDirectionType dir);
246 static void gtk_window_keys_changed (GtkWindow *window);
247 static void gtk_window_paint (GtkWidget *widget,
248 GdkRectangle *area);
249 static gint gtk_window_expose (GtkWidget *widget,
250 GdkEventExpose *event);
251 static void gtk_window_unset_transient_for (GtkWindow *window);
252 static void gtk_window_transient_parent_realized (GtkWidget *parent,
253 GtkWidget *window);
254 static void gtk_window_transient_parent_unrealized (GtkWidget *parent,
255 GtkWidget *window);
256
257 static GdkScreen *gtk_window_check_screen (GtkWindow *window);
258
259 static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window,
260 gboolean create);
261
262 static void gtk_window_move_resize (GtkWindow *window);
263 static gboolean gtk_window_compare_hints (GdkGeometry *geometry_a,
264 guint flags_a,
265 GdkGeometry *geometry_b,
266 guint flags_b);
267 static void gtk_window_constrain_size (GtkWindow *window,
268 GdkGeometry *geometry,
269 guint flags,
270 gint width,
271 gint height,
272 gint *new_width,
273 gint *new_height);
274 static void gtk_window_constrain_position (GtkWindow *window,
275 gint new_width,
276 gint new_height,
277 gint *x,
278 gint *y);
279 static void gtk_window_compute_hints (GtkWindow *window,
280 GdkGeometry *new_geometry,
281 guint *new_flags);
282 static void gtk_window_compute_configure_request (GtkWindow *window,
283 GdkRectangle *request,
284 GdkGeometry *geometry,
285 guint *flags);
286
287 static void gtk_window_set_default_size_internal (GtkWindow *window,
288 gboolean change_width,
289 gint width,
290 gboolean change_height,
291 gint height,
292 gboolean is_geometry);
293
294 static void update_themed_icon (GtkIconTheme *theme,
295 GtkWindow *window);
296 static GList *icon_list_from_theme (GtkWidget *widget,
297 const gchar *name);
298 static void gtk_window_realize_icon (GtkWindow *window);
299 static void gtk_window_unrealize_icon (GtkWindow *window);
300
301 static void gtk_window_notify_keys_changed (GtkWindow *window);
302 static GtkKeyHash *gtk_window_get_key_hash (GtkWindow *window);
303 static void gtk_window_free_key_hash (GtkWindow *window);
304 static void gtk_window_on_composited_changed (GdkScreen *screen,
305 GtkWindow *window);
306
307 static GSList *toplevel_list = NULL;
308 static guint window_signals[LAST_SIGNAL] = { 0 };
309 static GList *default_icon_list = NULL;
310 static gchar *default_icon_name = NULL;
311 static guint default_icon_serial = 0;
312 static gboolean disable_startup_notification = FALSE;
313 static gboolean sent_startup_notification = FALSE;
314
315 static GQuark quark_gtk_embedded = 0;
316 static GQuark quark_gtk_window_key_hash = 0;
317 static GQuark quark_gtk_window_default_icon_pixmap = 0;
318 static GQuark quark_gtk_window_icon_info = 0;
319 static GQuark quark_gtk_buildable_accels = 0;
320
321 static GtkBuildableIface *parent_buildable_iface;
322
323 static void gtk_window_set_property (GObject *object,
324 guint prop_id,
325 const GValue *value,
326 GParamSpec *pspec);
327 static void gtk_window_get_property (GObject *object,
328 guint prop_id,
329 GValue *value,
330 GParamSpec *pspec);
331
332 /* GtkBuildable */
333 static void gtk_window_buildable_interface_init (GtkBuildableIface *iface);
334 static void gtk_window_buildable_set_buildable_property (GtkBuildable *buildable,
335 GtkBuilder *builder,
336 const gchar *name,
337 const GValue *value);
338 static void gtk_window_buildable_parser_finished (GtkBuildable *buildable,
339 GtkBuilder *builder);
340 static gboolean gtk_window_buildable_custom_tag_start (GtkBuildable *buildable,
341 GtkBuilder *builder,
342 GObject *child,
343 const gchar *tagname,
344 GMarkupParser *parser,
345 gpointer *data);
346 static void gtk_window_buildable_custom_finished (GtkBuildable *buildable,
347 GtkBuilder *builder,
348 GObject *child,
349 const gchar *tagname,
350 gpointer user_data);
351
352
G_DEFINE_TYPE_WITH_CODE(GtkWindow,gtk_window,GTK_TYPE_BIN,G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,gtk_window_buildable_interface_init))353 G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
354 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
355 gtk_window_buildable_interface_init))
356
357 static void
358 add_tab_bindings (GtkBindingSet *binding_set,
359 GdkModifierType modifiers,
360 GtkDirectionType direction)
361 {
362 gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
363 "move-focus", 1,
364 GTK_TYPE_DIRECTION_TYPE, direction);
365 gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
366 "move-focus", 1,
367 GTK_TYPE_DIRECTION_TYPE, direction);
368 }
369
370 static void
add_arrow_bindings(GtkBindingSet * binding_set,guint keysym,GtkDirectionType direction)371 add_arrow_bindings (GtkBindingSet *binding_set,
372 guint keysym,
373 GtkDirectionType direction)
374 {
375 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
376
377 gtk_binding_entry_add_signal (binding_set, keysym, 0,
378 "move-focus", 1,
379 GTK_TYPE_DIRECTION_TYPE, direction);
380 gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
381 "move-focus", 1,
382 GTK_TYPE_DIRECTION_TYPE, direction);
383 gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
384 "move-focus", 1,
385 GTK_TYPE_DIRECTION_TYPE, direction);
386 gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
387 "move-focus", 1,
388 GTK_TYPE_DIRECTION_TYPE, direction);
389 }
390
391 static guint32
extract_time_from_startup_id(const gchar * startup_id)392 extract_time_from_startup_id (const gchar* startup_id)
393 {
394 gchar *timestr = g_strrstr (startup_id, "_TIME");
395 guint32 retval = GDK_CURRENT_TIME;
396
397 if (timestr)
398 {
399 gchar *end;
400 guint32 timestamp;
401
402 /* Skip past the "_TIME" part */
403 timestr += 5;
404
405 errno = 0;
406 timestamp = strtoul (timestr, &end, 0);
407 if (end != timestr && errno == 0)
408 retval = timestamp;
409 }
410
411 return retval;
412 }
413
414 static gboolean
startup_id_is_fake(const gchar * startup_id)415 startup_id_is_fake (const gchar* startup_id)
416 {
417 return strncmp (startup_id, "_TIME", 5) == 0;
418 }
419
420 static void
gtk_window_class_init(GtkWindowClass * klass)421 gtk_window_class_init (GtkWindowClass *klass)
422 {
423 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
424 GtkObjectClass *object_class;
425 GtkWidgetClass *widget_class;
426 GtkContainerClass *container_class;
427 GtkBindingSet *binding_set;
428
429 object_class = (GtkObjectClass*) klass;
430 widget_class = (GtkWidgetClass*) klass;
431 container_class = (GtkContainerClass*) klass;
432
433 quark_gtk_embedded = g_quark_from_static_string ("gtk-embedded");
434 quark_gtk_window_key_hash = g_quark_from_static_string ("gtk-window-key-hash");
435 quark_gtk_window_default_icon_pixmap = g_quark_from_static_string ("gtk-window-default-icon-pixmap");
436 quark_gtk_window_icon_info = g_quark_from_static_string ("gtk-window-icon-info");
437 quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
438
439 gobject_class->dispose = gtk_window_dispose;
440 gobject_class->finalize = gtk_window_finalize;
441
442 gobject_class->set_property = gtk_window_set_property;
443 gobject_class->get_property = gtk_window_get_property;
444
445 object_class->destroy = gtk_window_destroy;
446
447 widget_class->show = gtk_window_show;
448 widget_class->hide = gtk_window_hide;
449 widget_class->map = gtk_window_map;
450 widget_class->map_event = gtk_window_map_event;
451 widget_class->unmap = gtk_window_unmap;
452 widget_class->realize = gtk_window_realize;
453 widget_class->unrealize = gtk_window_unrealize;
454 widget_class->size_request = gtk_window_size_request;
455 widget_class->size_allocate = gtk_window_size_allocate;
456 widget_class->configure_event = gtk_window_configure_event;
457 widget_class->key_press_event = gtk_window_key_press_event;
458 widget_class->key_release_event = gtk_window_key_release_event;
459 widget_class->enter_notify_event = gtk_window_enter_notify_event;
460 widget_class->leave_notify_event = gtk_window_leave_notify_event;
461 widget_class->focus_in_event = gtk_window_focus_in_event;
462 widget_class->focus_out_event = gtk_window_focus_out_event;
463 widget_class->client_event = gtk_window_client_event;
464 widget_class->focus = gtk_window_focus;
465 widget_class->expose_event = gtk_window_expose;
466
467 container_class->check_resize = gtk_window_check_resize;
468
469 klass->set_focus = gtk_window_real_set_focus;
470 klass->frame_event = gtk_window_frame_event;
471
472 klass->activate_default = gtk_window_real_activate_default;
473 klass->activate_focus = gtk_window_real_activate_focus;
474 klass->move_focus = gtk_window_move_focus;
475 klass->keys_changed = gtk_window_keys_changed;
476
477 g_type_class_add_private (gobject_class, sizeof (GtkWindowPrivate));
478
479 /* Construct */
480 g_object_class_install_property (gobject_class,
481 PROP_TYPE,
482 g_param_spec_enum ("type",
483 P_("Window Type"),
484 P_("The type of the window"),
485 GTK_TYPE_WINDOW_TYPE,
486 GTK_WINDOW_TOPLEVEL,
487 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
488 /* Regular Props */
489 g_object_class_install_property (gobject_class,
490 PROP_TITLE,
491 g_param_spec_string ("title",
492 P_("Window Title"),
493 P_("The title of the window"),
494 NULL,
495 GTK_PARAM_READWRITE));
496
497 g_object_class_install_property (gobject_class,
498 PROP_ROLE,
499 g_param_spec_string ("role",
500 P_("Window Role"),
501 P_("Unique identifier for the window to be used when restoring a session"),
502 NULL,
503 GTK_PARAM_READWRITE));
504
505 /**
506 * GtkWindow:startup-id:
507 *
508 * The :startup-id is a write-only property for setting window's
509 * startup notification identifier. See gtk_window_set_startup_id()
510 * for more details.
511 *
512 * Since: 2.12
513 */
514 g_object_class_install_property (gobject_class,
515 PROP_STARTUP_ID,
516 g_param_spec_string ("startup-id",
517 P_("Startup ID"),
518 P_("Unique startup identifier for the window used by startup-notification"),
519 NULL,
520 GTK_PARAM_WRITABLE));
521
522 /**
523 * GtkWindow:allow-shrink:
524 *
525 * If %TRUE, the window has no mimimum size. Setting this to %TRUE is
526 * 99% of the time a bad idea.
527 *
528 * Deprecated: 2.22: Use GtkWindow:resizable property instead.
529 */
530 g_object_class_install_property (gobject_class,
531 PROP_ALLOW_SHRINK,
532 g_param_spec_boolean ("allow-shrink",
533 P_("Allow Shrink"),
534 /* xgettext:no-c-format */
535 P_("If TRUE, the window has no mimimum size. Setting this to TRUE is 99% of the time a bad idea"),
536 FALSE,
537 GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
538
539 /**
540 * GtkWindow:allow-grow:
541 *
542 * If %TRUE, users can expand the window beyond its minimum size.
543 *
544 * Deprecated: 2.22: Use GtkWindow:resizable property instead.
545 */
546 g_object_class_install_property (gobject_class,
547 PROP_ALLOW_GROW,
548 g_param_spec_boolean ("allow-grow",
549 P_("Allow Grow"),
550 P_("If TRUE, users can expand the window beyond its minimum size"),
551 TRUE,
552 GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
553
554 g_object_class_install_property (gobject_class,
555 PROP_RESIZABLE,
556 g_param_spec_boolean ("resizable",
557 P_("Resizable"),
558 P_("If TRUE, users can resize the window"),
559 TRUE,
560 GTK_PARAM_READWRITE));
561
562 g_object_class_install_property (gobject_class,
563 PROP_MODAL,
564 g_param_spec_boolean ("modal",
565 P_("Modal"),
566 P_("If TRUE, the window is modal (other windows are not usable while this one is up)"),
567 FALSE,
568 GTK_PARAM_READWRITE));
569
570 g_object_class_install_property (gobject_class,
571 PROP_WIN_POS,
572 g_param_spec_enum ("window-position",
573 P_("Window Position"),
574 P_("The initial position of the window"),
575 GTK_TYPE_WINDOW_POSITION,
576 GTK_WIN_POS_NONE,
577 GTK_PARAM_READWRITE));
578
579 g_object_class_install_property (gobject_class,
580 PROP_DEFAULT_WIDTH,
581 g_param_spec_int ("default-width",
582 P_("Default Width"),
583 P_("The default width of the window, used when initially showing the window"),
584 -1,
585 G_MAXINT,
586 -1,
587 GTK_PARAM_READWRITE));
588
589 g_object_class_install_property (gobject_class,
590 PROP_DEFAULT_HEIGHT,
591 g_param_spec_int ("default-height",
592 P_("Default Height"),
593 P_("The default height of the window, used when initially showing the window"),
594 -1,
595 G_MAXINT,
596 -1,
597 GTK_PARAM_READWRITE));
598
599 g_object_class_install_property (gobject_class,
600 PROP_DESTROY_WITH_PARENT,
601 g_param_spec_boolean ("destroy-with-parent",
602 P_("Destroy with Parent"),
603 P_("If this window should be destroyed when the parent is destroyed"),
604 FALSE,
605 GTK_PARAM_READWRITE));
606
607 g_object_class_install_property (gobject_class,
608 PROP_ICON,
609 g_param_spec_object ("icon",
610 P_("Icon"),
611 P_("Icon for this window"),
612 GDK_TYPE_PIXBUF,
613 GTK_PARAM_READWRITE));
614 g_object_class_install_property (gobject_class,
615 PROP_MNEMONICS_VISIBLE,
616 g_param_spec_boolean ("mnemonics-visible",
617 P_("Mnemonics Visible"),
618 P_("Whether mnemonics are currently visible in this window"),
619 TRUE,
620 GTK_PARAM_READWRITE));
621
622 /**
623 * GtkWindow:icon-name:
624 *
625 * The :icon-name property specifies the name of the themed icon to
626 * use as the window icon. See #GtkIconTheme for more details.
627 *
628 * Since: 2.6
629 */
630 g_object_class_install_property (gobject_class,
631 PROP_ICON_NAME,
632 g_param_spec_string ("icon-name",
633 P_("Icon Name"),
634 P_("Name of the themed icon for this window"),
635 NULL,
636 GTK_PARAM_READWRITE));
637
638 g_object_class_install_property (gobject_class,
639 PROP_SCREEN,
640 g_param_spec_object ("screen",
641 P_("Screen"),
642 P_("The screen where this window will be displayed"),
643 GDK_TYPE_SCREEN,
644 GTK_PARAM_READWRITE));
645
646 g_object_class_install_property (gobject_class,
647 PROP_IS_ACTIVE,
648 g_param_spec_boolean ("is-active",
649 P_("Is Active"),
650 P_("Whether the toplevel is the current active window"),
651 FALSE,
652 GTK_PARAM_READABLE));
653
654 g_object_class_install_property (gobject_class,
655 PROP_HAS_TOPLEVEL_FOCUS,
656 g_param_spec_boolean ("has-toplevel-focus",
657 P_("Focus in Toplevel"),
658 P_("Whether the input focus is within this GtkWindow"),
659 FALSE,
660 GTK_PARAM_READABLE));
661
662 g_object_class_install_property (gobject_class,
663 PROP_TYPE_HINT,
664 g_param_spec_enum ("type-hint",
665 P_("Type hint"),
666 P_("Hint to help the desktop environment understand what kind of window this is and how to treat it."),
667 GDK_TYPE_WINDOW_TYPE_HINT,
668 GDK_WINDOW_TYPE_HINT_NORMAL,
669 GTK_PARAM_READWRITE));
670
671 g_object_class_install_property (gobject_class,
672 PROP_SKIP_TASKBAR_HINT,
673 g_param_spec_boolean ("skip-taskbar-hint",
674 P_("Skip taskbar"),
675 P_("TRUE if the window should not be in the task bar."),
676 FALSE,
677 GTK_PARAM_READWRITE));
678
679 g_object_class_install_property (gobject_class,
680 PROP_SKIP_PAGER_HINT,
681 g_param_spec_boolean ("skip-pager-hint",
682 P_("Skip pager"),
683 P_("TRUE if the window should not be in the pager."),
684 FALSE,
685 GTK_PARAM_READWRITE));
686
687 g_object_class_install_property (gobject_class,
688 PROP_URGENCY_HINT,
689 g_param_spec_boolean ("urgency-hint",
690 P_("Urgent"),
691 P_("TRUE if the window should be brought to the user's attention."),
692 FALSE,
693 GTK_PARAM_READWRITE));
694
695 /**
696 * GtkWindow:accept-focus:
697 *
698 * Whether the window should receive the input focus.
699 *
700 * Since: 2.4
701 */
702 g_object_class_install_property (gobject_class,
703 PROP_ACCEPT_FOCUS,
704 g_param_spec_boolean ("accept-focus",
705 P_("Accept focus"),
706 P_("TRUE if the window should receive the input focus."),
707 TRUE,
708 GTK_PARAM_READWRITE));
709
710 /**
711 * GtkWindow:focus-on-map:
712 *
713 * Whether the window should receive the input focus when mapped.
714 *
715 * Since: 2.6
716 */
717 g_object_class_install_property (gobject_class,
718 PROP_FOCUS_ON_MAP,
719 g_param_spec_boolean ("focus-on-map",
720 P_("Focus on map"),
721 P_("TRUE if the window should receive the input focus when mapped."),
722 TRUE,
723 GTK_PARAM_READWRITE));
724
725 /**
726 * GtkWindow:decorated:
727 *
728 * Whether the window should be decorated by the window manager.
729 *
730 * Since: 2.4
731 */
732 g_object_class_install_property (gobject_class,
733 PROP_DECORATED,
734 g_param_spec_boolean ("decorated",
735 P_("Decorated"),
736 P_("Whether the window should be decorated by the window manager"),
737 TRUE,
738 GTK_PARAM_READWRITE));
739
740 /**
741 * GtkWindow:deletable:
742 *
743 * Whether the window frame should have a close button.
744 *
745 * Since: 2.10
746 */
747 g_object_class_install_property (gobject_class,
748 PROP_DELETABLE,
749 g_param_spec_boolean ("deletable",
750 P_("Deletable"),
751 P_("Whether the window frame should have a close button"),
752 TRUE,
753 GTK_PARAM_READWRITE));
754
755
756 /**
757 * GtkWindow:gravity:
758 *
759 * The window gravity of the window. See gtk_window_move() and #GdkGravity for
760 * more details about window gravity.
761 *
762 * Since: 2.4
763 */
764 g_object_class_install_property (gobject_class,
765 PROP_GRAVITY,
766 g_param_spec_enum ("gravity",
767 P_("Gravity"),
768 P_("The window gravity of the window"),
769 GDK_TYPE_GRAVITY,
770 GDK_GRAVITY_NORTH_WEST,
771 GTK_PARAM_READWRITE));
772
773
774 /**
775 * GtkWindow:transient-for:
776 *
777 * The transient parent of the window. See gtk_window_set_transient_for() for
778 * more details about transient windows.
779 *
780 * Since: 2.10
781 */
782 g_object_class_install_property (gobject_class,
783 PROP_TRANSIENT_FOR,
784 g_param_spec_object ("transient-for",
785 P_("Transient for Window"),
786 P_("The transient parent of the dialog"),
787 GTK_TYPE_WINDOW,
788 GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT));
789
790 /**
791 * GtkWindow:opacity:
792 *
793 * The requested opacity of the window. See gtk_window_set_opacity() for
794 * more details about window opacity.
795 *
796 * Since: 2.12
797 */
798 g_object_class_install_property (gobject_class,
799 PROP_OPACITY,
800 g_param_spec_double ("opacity",
801 P_("Opacity for Window"),
802 P_("The opacity of the window, from 0 to 1"),
803 0.0,
804 1.0,
805 1.0,
806 GTK_PARAM_READWRITE));
807
808 window_signals[SET_FOCUS] =
809 g_signal_new (I_("set-focus"),
810 G_TYPE_FROM_CLASS (gobject_class),
811 G_SIGNAL_RUN_LAST,
812 G_STRUCT_OFFSET (GtkWindowClass, set_focus),
813 NULL, NULL,
814 _gtk_marshal_VOID__OBJECT,
815 G_TYPE_NONE, 1,
816 GTK_TYPE_WIDGET);
817
818 window_signals[FRAME_EVENT] =
819 g_signal_new (I_("frame-event"),
820 G_TYPE_FROM_CLASS (gobject_class),
821 G_SIGNAL_RUN_LAST,
822 G_STRUCT_OFFSET(GtkWindowClass, frame_event),
823 _gtk_boolean_handled_accumulator, NULL,
824 _gtk_marshal_BOOLEAN__BOXED,
825 G_TYPE_BOOLEAN, 1,
826 GDK_TYPE_EVENT);
827
828 /**
829 * GtkWindow::activate-focus:
830 * @window: the window which received the signal
831 *
832 * The ::activate-focus signal is a
833 * <link linkend="keybinding-signals">keybinding signal</link>
834 * which gets emitted when the user activates the currently
835 * focused widget of @window.
836 */
837 window_signals[ACTIVATE_FOCUS] =
838 g_signal_new (I_("activate-focus"),
839 G_TYPE_FROM_CLASS (gobject_class),
840 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
841 G_STRUCT_OFFSET (GtkWindowClass, activate_focus),
842 NULL, NULL,
843 _gtk_marshal_VOID__VOID,
844 G_TYPE_NONE,
845 0);
846
847 /**
848 * GtkWindow::activate-default:
849 * @window: the window which received the signal
850 *
851 * The ::activate-default signal is a
852 * <link linkend="keybinding-signals">keybinding signal</link>
853 * which gets emitted when the user activates the default widget
854 * of @window.
855 */
856 window_signals[ACTIVATE_DEFAULT] =
857 g_signal_new (I_("activate-default"),
858 G_TYPE_FROM_CLASS (gobject_class),
859 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
860 G_STRUCT_OFFSET (GtkWindowClass, activate_default),
861 NULL, NULL,
862 _gtk_marshal_VOID__VOID,
863 G_TYPE_NONE,
864 0);
865
866 /**
867 * GtkWindow::keys-changed:
868 * @window: the window which received the signal
869 *
870 * The ::keys-changed signal gets emitted when the set of accelerators
871 * or mnemonics that are associated with @window changes.
872 */
873 window_signals[KEYS_CHANGED] =
874 g_signal_new (I_("keys-changed"),
875 G_TYPE_FROM_CLASS (gobject_class),
876 G_SIGNAL_RUN_FIRST,
877 G_STRUCT_OFFSET (GtkWindowClass, keys_changed),
878 NULL, NULL,
879 _gtk_marshal_VOID__VOID,
880 G_TYPE_NONE,
881 0);
882
883 /*
884 * Key bindings
885 */
886
887 binding_set = gtk_binding_set_by_class (klass);
888
889 gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
890 "activate-focus", 0);
891 gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0,
892 "activate-focus", 0);
893
894 gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
895 "activate-default", 0);
896 gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0,
897 "activate-default", 0);
898 gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
899 "activate-default", 0);
900
901 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
902 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
903 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
904 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
905
906 add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
907 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
908 add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
909 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
910 }
911
912 static void
gtk_window_init(GtkWindow * window)913 gtk_window_init (GtkWindow *window)
914 {
915 GdkColormap *colormap;
916 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
917
918 gtk_widget_set_has_window (GTK_WIDGET (window), TRUE);
919 _gtk_widget_set_is_toplevel (GTK_WIDGET (window), TRUE);
920
921 GTK_PRIVATE_SET_FLAG (window, GTK_ANCHORED);
922
923 gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
924
925 window->title = NULL;
926 window->wmclass_name = g_strdup (g_get_prgname ());
927 window->wmclass_class = g_strdup (gdk_get_program_class ());
928 window->wm_role = NULL;
929 window->geometry_info = NULL;
930 window->type = GTK_WINDOW_TOPLEVEL;
931 window->focus_widget = NULL;
932 window->default_widget = NULL;
933 window->configure_request_count = 0;
934 window->allow_shrink = FALSE;
935 window->allow_grow = TRUE;
936 window->configure_notify_received = FALSE;
937 window->position = GTK_WIN_POS_NONE;
938 window->need_default_size = TRUE;
939 window->need_default_position = TRUE;
940 window->modal = FALSE;
941 window->frame = NULL;
942 window->has_frame = FALSE;
943 window->frame_left = 0;
944 window->frame_right = 0;
945 window->frame_top = 0;
946 window->frame_bottom = 0;
947 window->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
948 window->gravity = GDK_GRAVITY_NORTH_WEST;
949 window->decorated = TRUE;
950 window->mnemonic_modifier = GDK_MOD1_MASK;
951 window->screen = gdk_screen_get_default ();
952
953 priv->accept_focus = TRUE;
954 priv->focus_on_map = TRUE;
955 priv->deletable = TRUE;
956 priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
957 priv->opacity = 1.0;
958 priv->startup_id = NULL;
959 priv->mnemonics_visible = TRUE;
960
961 colormap = _gtk_widget_peek_colormap ();
962 if (colormap)
963 gtk_widget_set_colormap (GTK_WIDGET (window), colormap);
964
965 g_object_ref_sink (window);
966 window->has_user_ref_count = TRUE;
967 toplevel_list = g_slist_prepend (toplevel_list, window);
968
969 gtk_decorated_window_init (window);
970
971 g_signal_connect (window->screen, "composited-changed",
972 G_CALLBACK (gtk_window_on_composited_changed), window);
973 }
974
975 static void
gtk_window_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)976 gtk_window_set_property (GObject *object,
977 guint prop_id,
978 const GValue *value,
979 GParamSpec *pspec)
980 {
981 GtkWindow *window;
982 GtkWindowPrivate *priv;
983
984 window = GTK_WINDOW (object);
985
986 priv = GTK_WINDOW_GET_PRIVATE (window);
987
988 switch (prop_id)
989 {
990 case PROP_TYPE:
991 window->type = g_value_get_enum (value);
992 break;
993 case PROP_TITLE:
994 gtk_window_set_title (window, g_value_get_string (value));
995 break;
996 case PROP_ROLE:
997 gtk_window_set_role (window, g_value_get_string (value));
998 break;
999 case PROP_STARTUP_ID:
1000 gtk_window_set_startup_id (window, g_value_get_string (value));
1001 break;
1002 case PROP_ALLOW_SHRINK:
1003 window->allow_shrink = g_value_get_boolean (value);
1004 gtk_widget_queue_resize (GTK_WIDGET (window));
1005 break;
1006 case PROP_ALLOW_GROW:
1007 window->allow_grow = g_value_get_boolean (value);
1008 gtk_widget_queue_resize (GTK_WIDGET (window));
1009 g_object_notify (G_OBJECT (window), "resizable");
1010 break;
1011 case PROP_RESIZABLE:
1012 window->allow_grow = g_value_get_boolean (value);
1013 gtk_widget_queue_resize (GTK_WIDGET (window));
1014 g_object_notify (G_OBJECT (window), "allow-grow");
1015 break;
1016 case PROP_MODAL:
1017 gtk_window_set_modal (window, g_value_get_boolean (value));
1018 break;
1019 case PROP_WIN_POS:
1020 gtk_window_set_position (window, g_value_get_enum (value));
1021 break;
1022 case PROP_DEFAULT_WIDTH:
1023 gtk_window_set_default_size_internal (window,
1024 TRUE, g_value_get_int (value),
1025 FALSE, -1, FALSE);
1026 break;
1027 case PROP_DEFAULT_HEIGHT:
1028 gtk_window_set_default_size_internal (window,
1029 FALSE, -1,
1030 TRUE, g_value_get_int (value), FALSE);
1031 break;
1032 case PROP_DESTROY_WITH_PARENT:
1033 gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value));
1034 break;
1035 case PROP_ICON:
1036 gtk_window_set_icon (window,
1037 g_value_get_object (value));
1038 break;
1039 case PROP_ICON_NAME:
1040 gtk_window_set_icon_name (window, g_value_get_string (value));
1041 break;
1042 case PROP_SCREEN:
1043 gtk_window_set_screen (window, g_value_get_object (value));
1044 break;
1045 case PROP_TYPE_HINT:
1046 gtk_window_set_type_hint (window,
1047 g_value_get_enum (value));
1048 break;
1049 case PROP_SKIP_TASKBAR_HINT:
1050 gtk_window_set_skip_taskbar_hint (window,
1051 g_value_get_boolean (value));
1052 break;
1053 case PROP_SKIP_PAGER_HINT:
1054 gtk_window_set_skip_pager_hint (window,
1055 g_value_get_boolean (value));
1056 break;
1057 case PROP_URGENCY_HINT:
1058 gtk_window_set_urgency_hint (window,
1059 g_value_get_boolean (value));
1060 break;
1061 case PROP_ACCEPT_FOCUS:
1062 gtk_window_set_accept_focus (window,
1063 g_value_get_boolean (value));
1064 break;
1065 case PROP_FOCUS_ON_MAP:
1066 gtk_window_set_focus_on_map (window,
1067 g_value_get_boolean (value));
1068 break;
1069 case PROP_DECORATED:
1070 gtk_window_set_decorated (window, g_value_get_boolean (value));
1071 break;
1072 case PROP_DELETABLE:
1073 gtk_window_set_deletable (window, g_value_get_boolean (value));
1074 break;
1075 case PROP_GRAVITY:
1076 gtk_window_set_gravity (window, g_value_get_enum (value));
1077 break;
1078 case PROP_TRANSIENT_FOR:
1079 gtk_window_set_transient_for (window, g_value_get_object (value));
1080 break;
1081 case PROP_OPACITY:
1082 gtk_window_set_opacity (window, g_value_get_double (value));
1083 break;
1084 case PROP_MNEMONICS_VISIBLE:
1085 gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
1086 break;
1087 default:
1088 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1089 break;
1090 }
1091 }
1092
1093 static void
gtk_window_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1094 gtk_window_get_property (GObject *object,
1095 guint prop_id,
1096 GValue *value,
1097 GParamSpec *pspec)
1098 {
1099 GtkWindow *window;
1100 GtkWindowPrivate *priv;
1101
1102 window = GTK_WINDOW (object);
1103 priv = GTK_WINDOW_GET_PRIVATE (window);
1104
1105 switch (prop_id)
1106 {
1107 GtkWindowGeometryInfo *info;
1108 case PROP_TYPE:
1109 g_value_set_enum (value, window->type);
1110 break;
1111 case PROP_ROLE:
1112 g_value_set_string (value, window->wm_role);
1113 break;
1114 case PROP_TITLE:
1115 g_value_set_string (value, window->title);
1116 break;
1117 case PROP_ALLOW_SHRINK:
1118 g_value_set_boolean (value, window->allow_shrink);
1119 break;
1120 case PROP_ALLOW_GROW:
1121 g_value_set_boolean (value, window->allow_grow);
1122 break;
1123 case PROP_RESIZABLE:
1124 g_value_set_boolean (value, window->allow_grow);
1125 break;
1126 case PROP_MODAL:
1127 g_value_set_boolean (value, window->modal);
1128 break;
1129 case PROP_WIN_POS:
1130 g_value_set_enum (value, window->position);
1131 break;
1132 case PROP_DEFAULT_WIDTH:
1133 info = gtk_window_get_geometry_info (window, FALSE);
1134 if (!info)
1135 g_value_set_int (value, -1);
1136 else
1137 g_value_set_int (value, info->default_width);
1138 break;
1139 case PROP_DEFAULT_HEIGHT:
1140 info = gtk_window_get_geometry_info (window, FALSE);
1141 if (!info)
1142 g_value_set_int (value, -1);
1143 else
1144 g_value_set_int (value, info->default_height);
1145 break;
1146 case PROP_DESTROY_WITH_PARENT:
1147 g_value_set_boolean (value, window->destroy_with_parent);
1148 break;
1149 case PROP_ICON:
1150 g_value_set_object (value, gtk_window_get_icon (window));
1151 break;
1152 case PROP_ICON_NAME:
1153 g_value_set_string (value, gtk_window_get_icon_name (window));
1154 break;
1155 case PROP_SCREEN:
1156 g_value_set_object (value, window->screen);
1157 break;
1158 case PROP_IS_ACTIVE:
1159 g_value_set_boolean (value, window->is_active);
1160 break;
1161 case PROP_HAS_TOPLEVEL_FOCUS:
1162 g_value_set_boolean (value, window->has_toplevel_focus);
1163 break;
1164 case PROP_TYPE_HINT:
1165 g_value_set_enum (value, priv->type_hint);
1166 break;
1167 case PROP_SKIP_TASKBAR_HINT:
1168 g_value_set_boolean (value,
1169 gtk_window_get_skip_taskbar_hint (window));
1170 break;
1171 case PROP_SKIP_PAGER_HINT:
1172 g_value_set_boolean (value,
1173 gtk_window_get_skip_pager_hint (window));
1174 break;
1175 case PROP_URGENCY_HINT:
1176 g_value_set_boolean (value,
1177 gtk_window_get_urgency_hint (window));
1178 break;
1179 case PROP_ACCEPT_FOCUS:
1180 g_value_set_boolean (value,
1181 gtk_window_get_accept_focus (window));
1182 break;
1183 case PROP_FOCUS_ON_MAP:
1184 g_value_set_boolean (value,
1185 gtk_window_get_focus_on_map (window));
1186 break;
1187 case PROP_DECORATED:
1188 g_value_set_boolean (value, gtk_window_get_decorated (window));
1189 break;
1190 case PROP_DELETABLE:
1191 g_value_set_boolean (value, gtk_window_get_deletable (window));
1192 break;
1193 case PROP_GRAVITY:
1194 g_value_set_enum (value, gtk_window_get_gravity (window));
1195 break;
1196 case PROP_TRANSIENT_FOR:
1197 g_value_set_object (value, gtk_window_get_transient_for (window));
1198 break;
1199 case PROP_OPACITY:
1200 g_value_set_double (value, gtk_window_get_opacity (window));
1201 break;
1202 case PROP_MNEMONICS_VISIBLE:
1203 g_value_set_boolean (value, priv->mnemonics_visible);
1204 break;
1205 default:
1206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1207 break;
1208 }
1209 }
1210
1211 static void
gtk_window_buildable_interface_init(GtkBuildableIface * iface)1212 gtk_window_buildable_interface_init (GtkBuildableIface *iface)
1213 {
1214 parent_buildable_iface = g_type_interface_peek_parent (iface);
1215 iface->set_buildable_property = gtk_window_buildable_set_buildable_property;
1216 iface->parser_finished = gtk_window_buildable_parser_finished;
1217 iface->custom_tag_start = gtk_window_buildable_custom_tag_start;
1218 iface->custom_finished = gtk_window_buildable_custom_finished;
1219 }
1220
1221 static void
gtk_window_buildable_set_buildable_property(GtkBuildable * buildable,GtkBuilder * builder,const gchar * name,const GValue * value)1222 gtk_window_buildable_set_buildable_property (GtkBuildable *buildable,
1223 GtkBuilder *builder,
1224 const gchar *name,
1225 const GValue *value)
1226 {
1227 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (buildable);
1228
1229 if (strcmp (name, "visible") == 0 && g_value_get_boolean (value))
1230 priv->builder_visible = TRUE;
1231 else
1232 parent_buildable_iface->set_buildable_property (buildable, builder, name, value);
1233 }
1234
1235 static void
gtk_window_buildable_parser_finished(GtkBuildable * buildable,GtkBuilder * builder)1236 gtk_window_buildable_parser_finished (GtkBuildable *buildable,
1237 GtkBuilder *builder)
1238 {
1239 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (buildable);
1240 GObject *object;
1241 GSList *accels, *l;
1242
1243 if (priv->builder_visible)
1244 gtk_widget_show (GTK_WIDGET (buildable));
1245
1246 accels = g_object_get_qdata (G_OBJECT (buildable), quark_gtk_buildable_accels);
1247 for (l = accels; l; l = l->next)
1248 {
1249 object = gtk_builder_get_object (builder, l->data);
1250 if (!object)
1251 {
1252 g_warning ("Unknown accel group %s specified in window %s",
1253 (const gchar*)l->data, gtk_buildable_get_name (buildable));
1254 continue;
1255 }
1256 gtk_window_add_accel_group (GTK_WINDOW (buildable),
1257 GTK_ACCEL_GROUP (object));
1258 g_free (l->data);
1259 }
1260
1261 g_object_set_qdata (G_OBJECT (buildable), quark_gtk_buildable_accels, NULL);
1262
1263 parent_buildable_iface->parser_finished (buildable, builder);
1264 }
1265
1266 typedef struct {
1267 GObject *object;
1268 GSList *items;
1269 } GSListSubParserData;
1270
1271 static void
window_start_element(GMarkupParseContext * context,const gchar * element_name,const gchar ** names,const gchar ** values,gpointer user_data,GError ** error)1272 window_start_element (GMarkupParseContext *context,
1273 const gchar *element_name,
1274 const gchar **names,
1275 const gchar **values,
1276 gpointer user_data,
1277 GError **error)
1278 {
1279 guint i;
1280 GSListSubParserData *data = (GSListSubParserData*)user_data;
1281
1282 if (strcmp (element_name, "group") == 0)
1283 {
1284 for (i = 0; names[i]; i++)
1285 {
1286 if (strcmp (names[i], "name") == 0)
1287 data->items = g_slist_prepend (data->items, g_strdup (values[i]));
1288 }
1289 }
1290 else if (strcmp (element_name, "accel-groups") == 0)
1291 return;
1292 else
1293 g_warning ("Unsupported tag type for GtkWindow: %s\n",
1294 element_name);
1295
1296 }
1297
1298 static const GMarkupParser window_parser =
1299 {
1300 window_start_element
1301 };
1302
1303 static gboolean
gtk_window_buildable_custom_tag_start(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const gchar * tagname,GMarkupParser * parser,gpointer * data)1304 gtk_window_buildable_custom_tag_start (GtkBuildable *buildable,
1305 GtkBuilder *builder,
1306 GObject *child,
1307 const gchar *tagname,
1308 GMarkupParser *parser,
1309 gpointer *data)
1310 {
1311 GSListSubParserData *parser_data;
1312
1313 if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
1314 tagname, parser, data))
1315 return TRUE;
1316
1317 if (strcmp (tagname, "accel-groups") == 0)
1318 {
1319 parser_data = g_slice_new0 (GSListSubParserData);
1320 parser_data->items = NULL;
1321 parser_data->object = G_OBJECT (buildable);
1322
1323 *parser = window_parser;
1324 *data = parser_data;
1325 return TRUE;
1326 }
1327
1328 return FALSE;
1329 }
1330
1331 static void
gtk_window_buildable_custom_finished(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const gchar * tagname,gpointer user_data)1332 gtk_window_buildable_custom_finished (GtkBuildable *buildable,
1333 GtkBuilder *builder,
1334 GObject *child,
1335 const gchar *tagname,
1336 gpointer user_data)
1337 {
1338 GSListSubParserData *data;
1339
1340 parent_buildable_iface->custom_finished (buildable, builder, child,
1341 tagname, user_data);
1342
1343 if (strcmp (tagname, "accel-groups") != 0)
1344 return;
1345
1346 data = (GSListSubParserData*)user_data;
1347
1348 g_object_set_qdata_full (G_OBJECT (buildable), quark_gtk_buildable_accels,
1349 data->items, (GDestroyNotify) g_slist_free);
1350
1351 g_slice_free (GSListSubParserData, data);
1352 }
1353
1354 /**
1355 * gtk_window_new:
1356 * @type: type of window
1357 *
1358 * Creates a new #GtkWindow, which is a toplevel window that can
1359 * contain other widgets. Nearly always, the type of the window should
1360 * be #GTK_WINDOW_TOPLEVEL. If you're implementing something like a
1361 * popup menu from scratch (which is a bad idea, just use #GtkMenu),
1362 * you might use #GTK_WINDOW_POPUP. #GTK_WINDOW_POPUP is not for
1363 * dialogs, though in some other toolkits dialogs are called "popups".
1364 * In GTK+, #GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip.
1365 * On X11, popup windows are not controlled by the <link
1366 * linkend="gtk-X11-arch">window manager</link>.
1367 *
1368 * If you simply want an undecorated window (no window borders), use
1369 * gtk_window_set_decorated(), don't use #GTK_WINDOW_POPUP.
1370 *
1371 * Return value: a new #GtkWindow.
1372 **/
1373 GtkWidget*
gtk_window_new(GtkWindowType type)1374 gtk_window_new (GtkWindowType type)
1375 {
1376 GtkWindow *window;
1377
1378 g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL);
1379
1380 window = g_object_new (GTK_TYPE_WINDOW, NULL);
1381
1382 window->type = type;
1383
1384 return GTK_WIDGET (window);
1385 }
1386
1387 /**
1388 * gtk_window_set_title:
1389 * @window: a #GtkWindow
1390 * @title: title of the window
1391 *
1392 * Sets the title of the #GtkWindow. The title of a window will be
1393 * displayed in its title bar; on the X Window System, the title bar
1394 * is rendered by the <link linkend="gtk-X11-arch">window
1395 * manager</link>, so exactly how the title appears to users may vary
1396 * according to a user's exact configuration. The title should help a
1397 * user distinguish this window from other windows they may have
1398 * open. A good title might include the application name and current
1399 * document filename, for example.
1400 *
1401 **/
1402 void
gtk_window_set_title(GtkWindow * window,const gchar * title)1403 gtk_window_set_title (GtkWindow *window,
1404 const gchar *title)
1405 {
1406 char *new_title;
1407
1408 g_return_if_fail (GTK_IS_WINDOW (window));
1409
1410 new_title = g_strdup (title);
1411 g_free (window->title);
1412 window->title = new_title;
1413
1414 if (gtk_widget_get_realized (GTK_WIDGET (window)))
1415 {
1416 gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
1417
1418 gtk_decorated_window_set_title (window, title);
1419 }
1420
1421 g_object_notify (G_OBJECT (window), "title");
1422 }
1423
1424 /**
1425 * gtk_window_get_title:
1426 * @window: a #GtkWindow
1427 *
1428 * Retrieves the title of the window. See gtk_window_set_title().
1429 *
1430 * Return value: the title of the window, or %NULL if none has
1431 * been set explicitely. The returned string is owned by the widget
1432 * and must not be modified or freed.
1433 **/
1434 const gchar *
gtk_window_get_title(GtkWindow * window)1435 gtk_window_get_title (GtkWindow *window)
1436 {
1437 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1438
1439 return window->title;
1440 }
1441
1442 /**
1443 * gtk_window_set_wmclass:
1444 * @window: a #GtkWindow
1445 * @wmclass_name: window name hint
1446 * @wmclass_class: window class hint
1447 *
1448 * Don't use this function. It sets the X Window System "class" and
1449 * "name" hints for a window. According to the ICCCM, you should
1450 * always set these to the same value for all windows in an
1451 * application, and GTK+ sets them to that value by default, so calling
1452 * this function is sort of pointless. However, you may want to call
1453 * gtk_window_set_role() on each window in your application, for the
1454 * benefit of the session manager. Setting the role allows the window
1455 * manager to restore window positions when loading a saved session.
1456 *
1457 **/
1458 void
gtk_window_set_wmclass(GtkWindow * window,const gchar * wmclass_name,const gchar * wmclass_class)1459 gtk_window_set_wmclass (GtkWindow *window,
1460 const gchar *wmclass_name,
1461 const gchar *wmclass_class)
1462 {
1463 g_return_if_fail (GTK_IS_WINDOW (window));
1464
1465 g_free (window->wmclass_name);
1466 window->wmclass_name = g_strdup (wmclass_name);
1467
1468 g_free (window->wmclass_class);
1469 window->wmclass_class = g_strdup (wmclass_class);
1470
1471 if (gtk_widget_get_realized (GTK_WIDGET (window)))
1472 g_warning ("gtk_window_set_wmclass: shouldn't set wmclass after window is realized!\n");
1473 }
1474
1475 /**
1476 * gtk_window_set_role:
1477 * @window: a #GtkWindow
1478 * @role: unique identifier for the window to be used when restoring a session
1479 *
1480 * This function is only useful on X11, not with other GTK+ targets.
1481 *
1482 * In combination with the window title, the window role allows a
1483 * <link linkend="gtk-X11-arch">window manager</link> to identify "the
1484 * same" window when an application is restarted. So for example you
1485 * might set the "toolbox" role on your app's toolbox window, so that
1486 * when the user restarts their session, the window manager can put
1487 * the toolbox back in the same place.
1488 *
1489 * If a window already has a unique title, you don't need to set the
1490 * role, since the WM can use the title to identify the window when
1491 * restoring the session.
1492 *
1493 **/
1494 void
gtk_window_set_role(GtkWindow * window,const gchar * role)1495 gtk_window_set_role (GtkWindow *window,
1496 const gchar *role)
1497 {
1498 char *new_role;
1499
1500 g_return_if_fail (GTK_IS_WINDOW (window));
1501
1502 new_role = g_strdup (role);
1503 g_free (window->wm_role);
1504 window->wm_role = new_role;
1505
1506 if (gtk_widget_get_realized (GTK_WIDGET (window)))
1507 gdk_window_set_role (GTK_WIDGET (window)->window, window->wm_role);
1508
1509 g_object_notify (G_OBJECT (window), "role");
1510 }
1511
1512 /**
1513 * gtk_window_set_startup_id:
1514 * @window: a #GtkWindow
1515 * @startup_id: a string with startup-notification identifier
1516 *
1517 * Startup notification identifiers are used by desktop environment to
1518 * track application startup, to provide user feedback and other
1519 * features. This function changes the corresponding property on the
1520 * underlying GdkWindow. Normally, startup identifier is managed
1521 * automatically and you should only use this function in special cases
1522 * like transferring focus from other processes. You should use this
1523 * function before calling gtk_window_present() or any equivalent
1524 * function generating a window map event.
1525 *
1526 * This function is only useful on X11, not with other GTK+ targets.
1527 *
1528 * Since: 2.12
1529 **/
1530 void
gtk_window_set_startup_id(GtkWindow * window,const gchar * startup_id)1531 gtk_window_set_startup_id (GtkWindow *window,
1532 const gchar *startup_id)
1533 {
1534 GtkWindowPrivate *priv;
1535
1536 g_return_if_fail (GTK_IS_WINDOW (window));
1537
1538 priv = GTK_WINDOW_GET_PRIVATE (window);
1539
1540 g_free (priv->startup_id);
1541 priv->startup_id = g_strdup (startup_id);
1542
1543 if (gtk_widget_get_realized (GTK_WIDGET (window)))
1544 {
1545 guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
1546
1547 #ifdef GDK_WINDOWING_X11
1548 if (timestamp != GDK_CURRENT_TIME)
1549 gdk_x11_window_set_user_time (GTK_WIDGET (window)->window, timestamp);
1550 #endif
1551
1552 /* Here we differentiate real and "fake" startup notification IDs,
1553 * constructed on purpose just to pass interaction timestamp
1554 */
1555 if (startup_id_is_fake (priv->startup_id))
1556 gtk_window_present_with_time (window, timestamp);
1557 else
1558 {
1559 gdk_window_set_startup_id (GTK_WIDGET (window)->window,
1560 priv->startup_id);
1561
1562 /* If window is mapped, terminate the startup-notification too */
1563 if (gtk_widget_get_mapped (GTK_WIDGET (window)) &&
1564 !disable_startup_notification)
1565 gdk_notify_startup_complete_with_id (priv->startup_id);
1566 }
1567 }
1568
1569 g_object_notify (G_OBJECT (window), "startup-id");
1570 }
1571
1572 /**
1573 * gtk_window_get_role:
1574 * @window: a #GtkWindow
1575 *
1576 * Returns the role of the window. See gtk_window_set_role() for
1577 * further explanation.
1578 *
1579 * Return value: the role of the window if set, or %NULL. The
1580 * returned is owned by the widget and must not be modified
1581 * or freed.
1582 **/
1583 const gchar *
gtk_window_get_role(GtkWindow * window)1584 gtk_window_get_role (GtkWindow *window)
1585 {
1586 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1587
1588 return window->wm_role;
1589 }
1590
1591 /**
1592 * gtk_window_set_focus:
1593 * @window: a #GtkWindow
1594 * @focus: (allow-none): widget to be the new focus widget, or %NULL to unset
1595 * any focus widget for the toplevel window.
1596 *
1597 * If @focus is not the current focus widget, and is focusable, sets
1598 * it as the focus widget for the window. If @focus is %NULL, unsets
1599 * the focus widget for this window. To set the focus to a particular
1600 * widget in the toplevel, it is usually more convenient to use
1601 * gtk_widget_grab_focus() instead of this function.
1602 **/
1603 void
gtk_window_set_focus(GtkWindow * window,GtkWidget * focus)1604 gtk_window_set_focus (GtkWindow *window,
1605 GtkWidget *focus)
1606 {
1607 g_return_if_fail (GTK_IS_WINDOW (window));
1608 if (focus)
1609 {
1610 g_return_if_fail (GTK_IS_WIDGET (focus));
1611 g_return_if_fail (gtk_widget_get_can_focus (focus));
1612 }
1613
1614 if (focus)
1615 gtk_widget_grab_focus (focus);
1616 else
1617 {
1618 /* Clear the existing focus chain, so that when we focus into
1619 * the window again, we start at the beginnning.
1620 */
1621 GtkWidget *widget = window->focus_widget;
1622 if (widget)
1623 {
1624 while (widget->parent)
1625 {
1626 widget = widget->parent;
1627 gtk_container_set_focus_child (GTK_CONTAINER (widget), NULL);
1628 }
1629 }
1630
1631 _gtk_window_internal_set_focus (window, NULL);
1632 }
1633 }
1634
1635 void
_gtk_window_internal_set_focus(GtkWindow * window,GtkWidget * focus)1636 _gtk_window_internal_set_focus (GtkWindow *window,
1637 GtkWidget *focus)
1638 {
1639 g_return_if_fail (GTK_IS_WINDOW (window));
1640
1641 if ((window->focus_widget != focus) ||
1642 (focus && !gtk_widget_has_focus (focus)))
1643 g_signal_emit (window, window_signals[SET_FOCUS], 0, focus);
1644 }
1645
1646 /**
1647 * gtk_window_set_default:
1648 * @window: a #GtkWindow
1649 * @default_widget: (allow-none): widget to be the default, or %NULL to unset the
1650 * default widget for the toplevel.
1651 *
1652 * The default widget is the widget that's activated when the user
1653 * presses Enter in a dialog (for example). This function sets or
1654 * unsets the default widget for a #GtkWindow about. When setting
1655 * (rather than unsetting) the default widget it's generally easier to
1656 * call gtk_widget_grab_focus() on the widget. Before making a widget
1657 * the default widget, you must set the #GTK_CAN_DEFAULT flag on the
1658 * widget you'd like to make the default using GTK_WIDGET_SET_FLAGS().
1659 **/
1660 void
gtk_window_set_default(GtkWindow * window,GtkWidget * default_widget)1661 gtk_window_set_default (GtkWindow *window,
1662 GtkWidget *default_widget)
1663 {
1664 g_return_if_fail (GTK_IS_WINDOW (window));
1665
1666 if (default_widget)
1667 g_return_if_fail (gtk_widget_get_can_default (default_widget));
1668
1669 if (window->default_widget != default_widget)
1670 {
1671 GtkWidget *old_default_widget = NULL;
1672
1673 if (default_widget)
1674 g_object_ref (default_widget);
1675
1676 if (window->default_widget)
1677 {
1678 old_default_widget = window->default_widget;
1679
1680 if (window->focus_widget != window->default_widget ||
1681 !gtk_widget_get_receives_default (window->default_widget))
1682 _gtk_widget_set_has_default (window->default_widget, FALSE);
1683 gtk_widget_queue_draw (window->default_widget);
1684 }
1685
1686 window->default_widget = default_widget;
1687
1688 if (window->default_widget)
1689 {
1690 if (window->focus_widget == NULL ||
1691 !gtk_widget_get_receives_default (window->focus_widget))
1692 _gtk_widget_set_has_default (window->default_widget, TRUE);
1693 gtk_widget_queue_draw (window->default_widget);
1694 }
1695
1696 if (old_default_widget)
1697 g_object_notify (G_OBJECT (old_default_widget), "has-default");
1698
1699 if (default_widget)
1700 {
1701 g_object_notify (G_OBJECT (default_widget), "has-default");
1702 g_object_unref (default_widget);
1703 }
1704 }
1705 }
1706
1707 /**
1708 * gtk_window_get_default_widget:
1709 * @window: a #GtkWindow
1710 *
1711 * Returns the default widget for @window. See gtk_window_set_default()
1712 * for more details.
1713 *
1714 * Returns: (transfer none): the default widget, or %NULL if there is none.
1715 *
1716 * Since: 2.14
1717 **/
1718 GtkWidget *
gtk_window_get_default_widget(GtkWindow * window)1719 gtk_window_get_default_widget (GtkWindow *window)
1720 {
1721 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1722
1723 return window->default_widget;
1724 }
1725
1726 static void
gtk_window_set_policy_internal(GtkWindow * window,gboolean allow_shrink,gboolean allow_grow,gboolean auto_shrink)1727 gtk_window_set_policy_internal (GtkWindow *window,
1728 gboolean allow_shrink,
1729 gboolean allow_grow,
1730 gboolean auto_shrink)
1731 {
1732 window->allow_shrink = (allow_shrink != FALSE);
1733 window->allow_grow = (allow_grow != FALSE);
1734
1735 g_object_freeze_notify (G_OBJECT (window));
1736 g_object_notify (G_OBJECT (window), "allow-shrink");
1737 g_object_notify (G_OBJECT (window), "allow-grow");
1738 g_object_notify (G_OBJECT (window), "resizable");
1739 g_object_thaw_notify (G_OBJECT (window));
1740
1741 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
1742 }
1743
1744 void
gtk_window_set_policy(GtkWindow * window,gboolean allow_shrink,gboolean allow_grow,gboolean auto_shrink)1745 gtk_window_set_policy (GtkWindow *window,
1746 gboolean allow_shrink,
1747 gboolean allow_grow,
1748 gboolean auto_shrink)
1749 {
1750 g_return_if_fail (GTK_IS_WINDOW (window));
1751
1752 gtk_window_set_policy_internal (window, allow_shrink, allow_grow, auto_shrink);
1753 }
1754
1755 static gboolean
handle_keys_changed(gpointer data)1756 handle_keys_changed (gpointer data)
1757 {
1758 GtkWindow *window;
1759
1760 window = GTK_WINDOW (data);
1761
1762 if (window->keys_changed_handler)
1763 {
1764 g_source_remove (window->keys_changed_handler);
1765 window->keys_changed_handler = 0;
1766 }
1767
1768 g_signal_emit (window, window_signals[KEYS_CHANGED], 0);
1769
1770 return FALSE;
1771 }
1772
1773 static void
gtk_window_notify_keys_changed(GtkWindow * window)1774 gtk_window_notify_keys_changed (GtkWindow *window)
1775 {
1776 if (!window->keys_changed_handler)
1777 window->keys_changed_handler = gdk_threads_add_idle (handle_keys_changed, window);
1778 }
1779
1780 /**
1781 * gtk_window_add_accel_group:
1782 * @window: window to attach accelerator group to
1783 * @accel_group: a #GtkAccelGroup
1784 *
1785 * Associate @accel_group with @window, such that calling
1786 * gtk_accel_groups_activate() on @window will activate accelerators
1787 * in @accel_group.
1788 **/
1789 void
gtk_window_add_accel_group(GtkWindow * window,GtkAccelGroup * accel_group)1790 gtk_window_add_accel_group (GtkWindow *window,
1791 GtkAccelGroup *accel_group)
1792 {
1793 g_return_if_fail (GTK_IS_WINDOW (window));
1794 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
1795
1796 _gtk_accel_group_attach (accel_group, G_OBJECT (window));
1797 g_signal_connect_object (accel_group, "accel-changed",
1798 G_CALLBACK (gtk_window_notify_keys_changed),
1799 window, G_CONNECT_SWAPPED);
1800 gtk_window_notify_keys_changed (window);
1801 }
1802
1803 /**
1804 * gtk_window_remove_accel_group:
1805 * @window: a #GtkWindow
1806 * @accel_group: a #GtkAccelGroup
1807 *
1808 * Reverses the effects of gtk_window_add_accel_group().
1809 **/
1810 void
gtk_window_remove_accel_group(GtkWindow * window,GtkAccelGroup * accel_group)1811 gtk_window_remove_accel_group (GtkWindow *window,
1812 GtkAccelGroup *accel_group)
1813 {
1814 g_return_if_fail (GTK_IS_WINDOW (window));
1815 g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
1816
1817 g_signal_handlers_disconnect_by_func (accel_group,
1818 gtk_window_notify_keys_changed,
1819 window);
1820 _gtk_accel_group_detach (accel_group, G_OBJECT (window));
1821 gtk_window_notify_keys_changed (window);
1822 }
1823
1824 static GtkMnemonicHash *
gtk_window_get_mnemonic_hash(GtkWindow * window,gboolean create)1825 gtk_window_get_mnemonic_hash (GtkWindow *window,
1826 gboolean create)
1827 {
1828 GtkWindowPrivate *private = GTK_WINDOW_GET_PRIVATE (window);
1829 if (!private->mnemonic_hash && create)
1830 private->mnemonic_hash = _gtk_mnemonic_hash_new ();
1831
1832 return private->mnemonic_hash;
1833 }
1834
1835 /**
1836 * gtk_window_add_mnemonic:
1837 * @window: a #GtkWindow
1838 * @keyval: the mnemonic
1839 * @target: the widget that gets activated by the mnemonic
1840 *
1841 * Adds a mnemonic to this window.
1842 */
1843 void
gtk_window_add_mnemonic(GtkWindow * window,guint keyval,GtkWidget * target)1844 gtk_window_add_mnemonic (GtkWindow *window,
1845 guint keyval,
1846 GtkWidget *target)
1847 {
1848 g_return_if_fail (GTK_IS_WINDOW (window));
1849 g_return_if_fail (GTK_IS_WIDGET (target));
1850
1851 _gtk_mnemonic_hash_add (gtk_window_get_mnemonic_hash (window, TRUE),
1852 keyval, target);
1853 gtk_window_notify_keys_changed (window);
1854 }
1855
1856 /**
1857 * gtk_window_remove_mnemonic:
1858 * @window: a #GtkWindow
1859 * @keyval: the mnemonic
1860 * @target: the widget that gets activated by the mnemonic
1861 *
1862 * Removes a mnemonic from this window.
1863 */
1864 void
gtk_window_remove_mnemonic(GtkWindow * window,guint keyval,GtkWidget * target)1865 gtk_window_remove_mnemonic (GtkWindow *window,
1866 guint keyval,
1867 GtkWidget *target)
1868 {
1869 g_return_if_fail (GTK_IS_WINDOW (window));
1870 g_return_if_fail (GTK_IS_WIDGET (target));
1871
1872 _gtk_mnemonic_hash_remove (gtk_window_get_mnemonic_hash (window, TRUE),
1873 keyval, target);
1874 gtk_window_notify_keys_changed (window);
1875 }
1876
1877 /**
1878 * gtk_window_mnemonic_activate:
1879 * @window: a #GtkWindow
1880 * @keyval: the mnemonic
1881 * @modifier: the modifiers
1882 * @returns: %TRUE if the activation is done.
1883 *
1884 * Activates the targets associated with the mnemonic.
1885 */
1886 gboolean
gtk_window_mnemonic_activate(GtkWindow * window,guint keyval,GdkModifierType modifier)1887 gtk_window_mnemonic_activate (GtkWindow *window,
1888 guint keyval,
1889 GdkModifierType modifier)
1890 {
1891 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1892
1893 if (window->mnemonic_modifier == (modifier & gtk_accelerator_get_default_mod_mask ()))
1894 {
1895 GtkMnemonicHash *mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
1896 if (mnemonic_hash)
1897 return _gtk_mnemonic_hash_activate (mnemonic_hash, keyval);
1898 }
1899
1900 return FALSE;
1901 }
1902
1903 /**
1904 * gtk_window_set_mnemonic_modifier:
1905 * @window: a #GtkWindow
1906 * @modifier: the modifier mask used to activate
1907 * mnemonics on this window.
1908 *
1909 * Sets the mnemonic modifier for this window.
1910 **/
1911 void
gtk_window_set_mnemonic_modifier(GtkWindow * window,GdkModifierType modifier)1912 gtk_window_set_mnemonic_modifier (GtkWindow *window,
1913 GdkModifierType modifier)
1914 {
1915 g_return_if_fail (GTK_IS_WINDOW (window));
1916 g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0);
1917
1918 window->mnemonic_modifier = modifier;
1919 gtk_window_notify_keys_changed (window);
1920 }
1921
1922 /**
1923 * gtk_window_get_mnemonic_modifier:
1924 * @window: a #GtkWindow
1925 *
1926 * Returns the mnemonic modifier for this window. See
1927 * gtk_window_set_mnemonic_modifier().
1928 *
1929 * Return value: the modifier mask used to activate
1930 * mnemonics on this window.
1931 **/
1932 GdkModifierType
gtk_window_get_mnemonic_modifier(GtkWindow * window)1933 gtk_window_get_mnemonic_modifier (GtkWindow *window)
1934 {
1935 g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
1936
1937 return window->mnemonic_modifier;
1938 }
1939
1940 /**
1941 * gtk_window_set_position:
1942 * @window: a #GtkWindow.
1943 * @position: a position constraint.
1944 *
1945 * Sets a position constraint for this window. If the old or new
1946 * constraint is %GTK_WIN_POS_CENTER_ALWAYS, this will also cause
1947 * the window to be repositioned to satisfy the new constraint.
1948 **/
1949 void
gtk_window_set_position(GtkWindow * window,GtkWindowPosition position)1950 gtk_window_set_position (GtkWindow *window,
1951 GtkWindowPosition position)
1952 {
1953 g_return_if_fail (GTK_IS_WINDOW (window));
1954
1955 if (position == GTK_WIN_POS_CENTER_ALWAYS ||
1956 window->position == GTK_WIN_POS_CENTER_ALWAYS)
1957 {
1958 GtkWindowGeometryInfo *info;
1959
1960 info = gtk_window_get_geometry_info (window, TRUE);
1961
1962 /* this flag causes us to re-request the CENTER_ALWAYS
1963 * constraint in gtk_window_move_resize(), see
1964 * comment in that function.
1965 */
1966 info->position_constraints_changed = TRUE;
1967
1968 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
1969 }
1970
1971 window->position = position;
1972
1973 g_object_notify (G_OBJECT (window), "window-position");
1974 }
1975
1976 /**
1977 * gtk_window_activate_focus:
1978 * @window: a #GtkWindow
1979 *
1980 * Activates the current focused widget within the window.
1981 *
1982 * Return value: %TRUE if a widget got activated.
1983 **/
1984 gboolean
gtk_window_activate_focus(GtkWindow * window)1985 gtk_window_activate_focus (GtkWindow *window)
1986 {
1987 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1988
1989 if (window->focus_widget && gtk_widget_is_sensitive (window->focus_widget))
1990 return gtk_widget_activate (window->focus_widget);
1991
1992 return FALSE;
1993 }
1994
1995 /**
1996 * gtk_window_get_focus:
1997 * @window: a #GtkWindow
1998 *
1999 * Retrieves the current focused widget within the window.
2000 * Note that this is the widget that would have the focus
2001 * if the toplevel window focused; if the toplevel window
2002 * is not focused then <literal>gtk_widget_has_focus (widget)</literal> will
2003 * not be %TRUE for the widget.
2004 *
2005 * Return value: (transfer none): the currently focused widget, or %NULL if there is none.
2006 **/
2007 GtkWidget *
gtk_window_get_focus(GtkWindow * window)2008 gtk_window_get_focus (GtkWindow *window)
2009 {
2010 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2011
2012 return window->focus_widget;
2013 }
2014
2015 /**
2016 * gtk_window_activate_default:
2017 * @window: a #GtkWindow
2018 *
2019 * Activates the default widget for the window, unless the current
2020 * focused widget has been configured to receive the default action
2021 * (see gtk_widget_set_receives_default()), in which case the
2022 * focused widget is activated.
2023 *
2024 * Return value: %TRUE if a widget got activated.
2025 **/
2026 gboolean
gtk_window_activate_default(GtkWindow * window)2027 gtk_window_activate_default (GtkWindow *window)
2028 {
2029 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2030
2031 if (window->default_widget && gtk_widget_is_sensitive (window->default_widget) &&
2032 (!window->focus_widget || !gtk_widget_get_receives_default (window->focus_widget)))
2033 return gtk_widget_activate (window->default_widget);
2034 else if (window->focus_widget && gtk_widget_is_sensitive (window->focus_widget))
2035 return gtk_widget_activate (window->focus_widget);
2036
2037 return FALSE;
2038 }
2039
2040 /**
2041 * gtk_window_set_modal:
2042 * @window: a #GtkWindow
2043 * @modal: whether the window is modal
2044 *
2045 * Sets a window modal or non-modal. Modal windows prevent interaction
2046 * with other windows in the same application. To keep modal dialogs
2047 * on top of main application windows, use
2048 * gtk_window_set_transient_for() to make the dialog transient for the
2049 * parent; most <link linkend="gtk-X11-arch">window managers</link>
2050 * will then disallow lowering the dialog below the parent.
2051 *
2052 *
2053 **/
2054 void
gtk_window_set_modal(GtkWindow * window,gboolean modal)2055 gtk_window_set_modal (GtkWindow *window,
2056 gboolean modal)
2057 {
2058 GtkWidget *widget;
2059
2060 g_return_if_fail (GTK_IS_WINDOW (window));
2061
2062 modal = modal != FALSE;
2063 if (window->modal == modal)
2064 return;
2065
2066 window->modal = modal;
2067 widget = GTK_WIDGET (window);
2068
2069 /* adjust desired modality state */
2070 if (gtk_widget_get_realized (widget))
2071 {
2072 if (window->modal)
2073 gdk_window_set_modal_hint (widget->window, TRUE);
2074 else
2075 gdk_window_set_modal_hint (widget->window, FALSE);
2076 }
2077
2078 if (gtk_widget_get_visible (widget))
2079 {
2080 if (window->modal)
2081 gtk_grab_add (widget);
2082 else
2083 gtk_grab_remove (widget);
2084 }
2085
2086 g_object_notify (G_OBJECT (window), "modal");
2087 }
2088
2089 /**
2090 * gtk_window_get_modal:
2091 * @window: a #GtkWindow
2092 *
2093 * Returns whether the window is modal. See gtk_window_set_modal().
2094 *
2095 * Return value: %TRUE if the window is set to be modal and
2096 * establishes a grab when shown
2097 **/
2098 gboolean
gtk_window_get_modal(GtkWindow * window)2099 gtk_window_get_modal (GtkWindow *window)
2100 {
2101 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2102
2103 return window->modal;
2104 }
2105
2106 /**
2107 * gtk_window_list_toplevels:
2108 *
2109 * Returns a list of all existing toplevel windows. The widgets
2110 * in the list are not individually referenced. If you want
2111 * to iterate through the list and perform actions involving
2112 * callbacks that might destroy the widgets, you <emphasis>must</emphasis> call
2113 * <literal>g_list_foreach (result, (GFunc)g_object_ref, NULL)</literal> first, and
2114 * then unref all the widgets afterwards.
2115 *
2116 * Return value: (element-type GtkWidget) (transfer container): list of toplevel widgets
2117 **/
2118 GList*
gtk_window_list_toplevels(void)2119 gtk_window_list_toplevels (void)
2120 {
2121 GList *list = NULL;
2122 GSList *slist;
2123
2124 for (slist = toplevel_list; slist; slist = slist->next)
2125 list = g_list_prepend (list, slist->data);
2126
2127 return list;
2128 }
2129
2130 void
gtk_window_add_embedded_xid(GtkWindow * window,GdkNativeWindow xid)2131 gtk_window_add_embedded_xid (GtkWindow *window, GdkNativeWindow xid)
2132 {
2133 GList *embedded_windows;
2134
2135 g_return_if_fail (GTK_IS_WINDOW (window));
2136
2137 embedded_windows = g_object_get_qdata (G_OBJECT (window), quark_gtk_embedded);
2138 if (embedded_windows)
2139 g_object_steal_qdata (G_OBJECT (window), quark_gtk_embedded);
2140 embedded_windows = g_list_prepend (embedded_windows,
2141 GUINT_TO_POINTER (xid));
2142
2143 g_object_set_qdata_full (G_OBJECT (window), quark_gtk_embedded,
2144 embedded_windows,
2145 embedded_windows ?
2146 (GDestroyNotify) g_list_free : NULL);
2147 }
2148
2149 void
gtk_window_remove_embedded_xid(GtkWindow * window,GdkNativeWindow xid)2150 gtk_window_remove_embedded_xid (GtkWindow *window, GdkNativeWindow xid)
2151 {
2152 GList *embedded_windows;
2153 GList *node;
2154
2155 g_return_if_fail (GTK_IS_WINDOW (window));
2156
2157 embedded_windows = g_object_get_qdata (G_OBJECT (window), quark_gtk_embedded);
2158 if (embedded_windows)
2159 g_object_steal_qdata (G_OBJECT (window), quark_gtk_embedded);
2160
2161 node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
2162 if (node)
2163 {
2164 embedded_windows = g_list_remove_link (embedded_windows, node);
2165 g_list_free_1 (node);
2166 }
2167
2168 g_object_set_qdata_full (G_OBJECT (window), quark_gtk_embedded,
2169 embedded_windows,
2170 embedded_windows ?
2171 (GDestroyNotify) g_list_free : NULL);
2172 }
2173
2174 void
_gtk_window_reposition(GtkWindow * window,gint x,gint y)2175 _gtk_window_reposition (GtkWindow *window,
2176 gint x,
2177 gint y)
2178 {
2179 g_return_if_fail (GTK_IS_WINDOW (window));
2180
2181 gtk_window_move (window, x, y);
2182 }
2183
2184 static void
gtk_window_dispose(GObject * object)2185 gtk_window_dispose (GObject *object)
2186 {
2187 GtkWindow *window = GTK_WINDOW (object);
2188
2189 gtk_window_set_focus (window, NULL);
2190 gtk_window_set_default (window, NULL);
2191
2192 G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object);
2193 }
2194
2195 static void
parent_destroyed_callback(GtkWindow * parent,GtkWindow * child)2196 parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
2197 {
2198 gtk_widget_destroy (GTK_WIDGET (child));
2199 }
2200
2201 static void
connect_parent_destroyed(GtkWindow * window)2202 connect_parent_destroyed (GtkWindow *window)
2203 {
2204 if (window->transient_parent)
2205 {
2206 g_signal_connect (window->transient_parent,
2207 "destroy",
2208 G_CALLBACK (parent_destroyed_callback),
2209 window);
2210 }
2211 }
2212
2213 static void
disconnect_parent_destroyed(GtkWindow * window)2214 disconnect_parent_destroyed (GtkWindow *window)
2215 {
2216 if (window->transient_parent)
2217 {
2218 g_signal_handlers_disconnect_by_func (window->transient_parent,
2219 parent_destroyed_callback,
2220 window);
2221 }
2222 }
2223
2224 static void
gtk_window_transient_parent_realized(GtkWidget * parent,GtkWidget * window)2225 gtk_window_transient_parent_realized (GtkWidget *parent,
2226 GtkWidget *window)
2227 {
2228 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2229 gdk_window_set_transient_for (window->window, parent->window);
2230 }
2231
2232 static void
gtk_window_transient_parent_unrealized(GtkWidget * parent,GtkWidget * window)2233 gtk_window_transient_parent_unrealized (GtkWidget *parent,
2234 GtkWidget *window)
2235 {
2236 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2237 gdk_property_delete (window->window,
2238 gdk_atom_intern_static_string ("WM_TRANSIENT_FOR"));
2239 }
2240
2241 static void
gtk_window_transient_parent_screen_changed(GtkWindow * parent,GParamSpec * pspec,GtkWindow * window)2242 gtk_window_transient_parent_screen_changed (GtkWindow *parent,
2243 GParamSpec *pspec,
2244 GtkWindow *window)
2245 {
2246 gtk_window_set_screen (window, parent->screen);
2247 }
2248
2249 static void
gtk_window_unset_transient_for(GtkWindow * window)2250 gtk_window_unset_transient_for (GtkWindow *window)
2251 {
2252 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
2253
2254 if (window->transient_parent)
2255 {
2256 g_signal_handlers_disconnect_by_func (window->transient_parent,
2257 gtk_window_transient_parent_realized,
2258 window);
2259 g_signal_handlers_disconnect_by_func (window->transient_parent,
2260 gtk_window_transient_parent_unrealized,
2261 window);
2262 g_signal_handlers_disconnect_by_func (window->transient_parent,
2263 gtk_window_transient_parent_screen_changed,
2264 window);
2265 g_signal_handlers_disconnect_by_func (window->transient_parent,
2266 gtk_widget_destroyed,
2267 &window->transient_parent);
2268
2269 if (window->destroy_with_parent)
2270 disconnect_parent_destroyed (window);
2271
2272 window->transient_parent = NULL;
2273
2274 if (priv->transient_parent_group)
2275 {
2276 priv->transient_parent_group = FALSE;
2277 gtk_window_group_remove_window (window->group,
2278 window);
2279 }
2280 }
2281 }
2282
2283 /**
2284 * gtk_window_set_transient_for:
2285 * @window: a #GtkWindow
2286 * @parent: (allow-none): parent window, or %NULL
2287 *
2288 * Dialog windows should be set transient for the main application
2289 * window they were spawned from. This allows <link
2290 * linkend="gtk-X11-arch">window managers</link> to e.g. keep the
2291 * dialog on top of the main window, or center the dialog over the
2292 * main window. gtk_dialog_new_with_buttons() and other convenience
2293 * functions in GTK+ will sometimes call
2294 * gtk_window_set_transient_for() on your behalf.
2295 *
2296 * Passing %NULL for @parent unsets the current transient window.
2297 *
2298 * On Windows, this function puts the child window on top of the parent,
2299 * much as the window manager would have done on X.
2300 */
2301 void
gtk_window_set_transient_for(GtkWindow * window,GtkWindow * parent)2302 gtk_window_set_transient_for (GtkWindow *window,
2303 GtkWindow *parent)
2304 {
2305 GtkWindowPrivate *priv;
2306
2307 g_return_if_fail (GTK_IS_WINDOW (window));
2308 g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
2309 g_return_if_fail (window != parent);
2310
2311 priv = GTK_WINDOW_GET_PRIVATE (window);
2312
2313 if (window->transient_parent)
2314 {
2315 if (gtk_widget_get_realized (GTK_WIDGET (window)) &&
2316 gtk_widget_get_realized (GTK_WIDGET (window->transient_parent)) &&
2317 (!parent || !gtk_widget_get_realized (GTK_WIDGET (parent))))
2318 gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
2319 GTK_WIDGET (window));
2320
2321 gtk_window_unset_transient_for (window);
2322 }
2323
2324 window->transient_parent = parent;
2325
2326 if (parent)
2327 {
2328 g_signal_connect (parent, "destroy",
2329 G_CALLBACK (gtk_widget_destroyed),
2330 &window->transient_parent);
2331 g_signal_connect (parent, "realize",
2332 G_CALLBACK (gtk_window_transient_parent_realized),
2333 window);
2334 g_signal_connect (parent, "unrealize",
2335 G_CALLBACK (gtk_window_transient_parent_unrealized),
2336 window);
2337 g_signal_connect (parent, "notify::screen",
2338 G_CALLBACK (gtk_window_transient_parent_screen_changed),
2339 window);
2340
2341 gtk_window_set_screen (window, parent->screen);
2342
2343 if (window->destroy_with_parent)
2344 connect_parent_destroyed (window);
2345
2346 if (gtk_widget_get_realized (GTK_WIDGET (window)) &&
2347 gtk_widget_get_realized (GTK_WIDGET (parent)))
2348 gtk_window_transient_parent_realized (GTK_WIDGET (parent),
2349 GTK_WIDGET (window));
2350
2351 if (parent->group)
2352 {
2353 gtk_window_group_add_window (parent->group, window);
2354 priv->transient_parent_group = TRUE;
2355 }
2356 }
2357 }
2358
2359 /**
2360 * gtk_window_get_transient_for:
2361 * @window: a #GtkWindow
2362 *
2363 * Fetches the transient parent for this window. See
2364 * gtk_window_set_transient_for().
2365 *
2366 * Return value: (transfer none): the transient parent for this window, or %NULL
2367 * if no transient parent has been set.
2368 **/
2369 GtkWindow *
gtk_window_get_transient_for(GtkWindow * window)2370 gtk_window_get_transient_for (GtkWindow *window)
2371 {
2372 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2373
2374 return window->transient_parent;
2375 }
2376
2377 /**
2378 * gtk_window_set_opacity:
2379 * @window: a #GtkWindow
2380 * @opacity: desired opacity, between 0 and 1
2381 *
2382 * Request the windowing system to make @window partially transparent,
2383 * with opacity 0 being fully transparent and 1 fully opaque. (Values
2384 * of the opacity parameter are clamped to the [0,1] range.) On X11
2385 * this has any effect only on X screens with a compositing manager
2386 * running. See gtk_widget_is_composited(). On Windows it should work
2387 * always.
2388 *
2389 * Note that setting a window's opacity after the window has been
2390 * shown causes it to flicker once on Windows.
2391 *
2392 * Since: 2.12
2393 **/
2394 void
gtk_window_set_opacity(GtkWindow * window,gdouble opacity)2395 gtk_window_set_opacity (GtkWindow *window,
2396 gdouble opacity)
2397 {
2398 GtkWindowPrivate *priv;
2399
2400 g_return_if_fail (GTK_IS_WINDOW (window));
2401
2402 priv = GTK_WINDOW_GET_PRIVATE (window);
2403
2404 if (opacity < 0.0)
2405 opacity = 0.0;
2406 else if (opacity > 1.0)
2407 opacity = 1.0;
2408
2409 priv->opacity_set = TRUE;
2410 priv->opacity = opacity;
2411
2412 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2413 gdk_window_set_opacity (GTK_WIDGET (window)->window, priv->opacity);
2414 }
2415
2416 /**
2417 * gtk_window_get_opacity:
2418 * @window: a #GtkWindow
2419 *
2420 * Fetches the requested opacity for this window. See
2421 * gtk_window_set_opacity().
2422 *
2423 * Return value: the requested opacity for this window.
2424 *
2425 * Since: 2.12
2426 **/
2427 gdouble
gtk_window_get_opacity(GtkWindow * window)2428 gtk_window_get_opacity (GtkWindow *window)
2429 {
2430 GtkWindowPrivate *priv;
2431
2432 g_return_val_if_fail (GTK_IS_WINDOW (window), 0.0);
2433
2434 priv = GTK_WINDOW_GET_PRIVATE (window);
2435
2436 return priv->opacity;
2437 }
2438
2439 /**
2440 * gtk_window_set_type_hint:
2441 * @window: a #GtkWindow
2442 * @hint: the window type
2443 *
2444 * By setting the type hint for the window, you allow the window
2445 * manager to decorate and handle the window in a way which is
2446 * suitable to the function of the window in your application.
2447 *
2448 * This function should be called before the window becomes visible.
2449 *
2450 * gtk_dialog_new_with_buttons() and other convenience functions in GTK+
2451 * will sometimes call gtk_window_set_type_hint() on your behalf.
2452 *
2453 **/
2454 void
gtk_window_set_type_hint(GtkWindow * window,GdkWindowTypeHint hint)2455 gtk_window_set_type_hint (GtkWindow *window,
2456 GdkWindowTypeHint hint)
2457 {
2458 GtkWindowPrivate *priv;
2459
2460 g_return_if_fail (GTK_IS_WINDOW (window));
2461 g_return_if_fail (!gtk_widget_get_mapped (GTK_WIDGET (window)));
2462
2463 priv = GTK_WINDOW_GET_PRIVATE (window);
2464
2465 if (hint < GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU)
2466 window->type_hint = hint;
2467 else
2468 window->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
2469
2470 priv->reset_type_hint = TRUE;
2471 priv->type_hint = hint;
2472 }
2473
2474 /**
2475 * gtk_window_get_type_hint:
2476 * @window: a #GtkWindow
2477 *
2478 * Gets the type hint for this window. See gtk_window_set_type_hint().
2479 *
2480 * Return value: the type hint for @window.
2481 **/
2482 GdkWindowTypeHint
gtk_window_get_type_hint(GtkWindow * window)2483 gtk_window_get_type_hint (GtkWindow *window)
2484 {
2485 GtkWindowPrivate *priv;
2486
2487 g_return_val_if_fail (GTK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
2488
2489 priv = GTK_WINDOW_GET_PRIVATE (window);
2490
2491 return priv->type_hint;
2492 }
2493
2494 /**
2495 * gtk_window_set_skip_taskbar_hint:
2496 * @window: a #GtkWindow
2497 * @setting: %TRUE to keep this window from appearing in the task bar
2498 *
2499 * Windows may set a hint asking the desktop environment not to display
2500 * the window in the task bar. This function sets this hint.
2501 *
2502 * Since: 2.2
2503 **/
2504 void
gtk_window_set_skip_taskbar_hint(GtkWindow * window,gboolean setting)2505 gtk_window_set_skip_taskbar_hint (GtkWindow *window,
2506 gboolean setting)
2507 {
2508 GtkWindowPrivate *priv;
2509
2510 g_return_if_fail (GTK_IS_WINDOW (window));
2511
2512 priv = GTK_WINDOW_GET_PRIVATE (window);
2513
2514 setting = setting != FALSE;
2515
2516 if (priv->skips_taskbar != setting)
2517 {
2518 priv->skips_taskbar = setting;
2519 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2520 gdk_window_set_skip_taskbar_hint (GTK_WIDGET (window)->window,
2521 priv->skips_taskbar);
2522 g_object_notify (G_OBJECT (window), "skip-taskbar-hint");
2523 }
2524 }
2525
2526 /**
2527 * gtk_window_get_skip_taskbar_hint:
2528 * @window: a #GtkWindow
2529 *
2530 * Gets the value set by gtk_window_set_skip_taskbar_hint()
2531 *
2532 * Return value: %TRUE if window shouldn't be in taskbar
2533 *
2534 * Since: 2.2
2535 **/
2536 gboolean
gtk_window_get_skip_taskbar_hint(GtkWindow * window)2537 gtk_window_get_skip_taskbar_hint (GtkWindow *window)
2538 {
2539 GtkWindowPrivate *priv;
2540
2541 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2542
2543 priv = GTK_WINDOW_GET_PRIVATE (window);
2544
2545 return priv->skips_taskbar;
2546 }
2547
2548 /**
2549 * gtk_window_set_skip_pager_hint:
2550 * @window: a #GtkWindow
2551 * @setting: %TRUE to keep this window from appearing in the pager
2552 *
2553 * Windows may set a hint asking the desktop environment not to display
2554 * the window in the pager. This function sets this hint.
2555 * (A "pager" is any desktop navigation tool such as a workspace
2556 * switcher that displays a thumbnail representation of the windows
2557 * on the screen.)
2558 *
2559 * Since: 2.2
2560 **/
2561 void
gtk_window_set_skip_pager_hint(GtkWindow * window,gboolean setting)2562 gtk_window_set_skip_pager_hint (GtkWindow *window,
2563 gboolean setting)
2564 {
2565 GtkWindowPrivate *priv;
2566
2567 g_return_if_fail (GTK_IS_WINDOW (window));
2568
2569 priv = GTK_WINDOW_GET_PRIVATE (window);
2570
2571 setting = setting != FALSE;
2572
2573 if (priv->skips_pager != setting)
2574 {
2575 priv->skips_pager = setting;
2576 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2577 gdk_window_set_skip_pager_hint (GTK_WIDGET (window)->window,
2578 priv->skips_pager);
2579 g_object_notify (G_OBJECT (window), "skip-pager-hint");
2580 }
2581 }
2582
2583 /**
2584 * gtk_window_get_skip_pager_hint:
2585 * @window: a #GtkWindow
2586 *
2587 * Gets the value set by gtk_window_set_skip_pager_hint().
2588 *
2589 * Return value: %TRUE if window shouldn't be in pager
2590 *
2591 * Since: 2.2
2592 **/
2593 gboolean
gtk_window_get_skip_pager_hint(GtkWindow * window)2594 gtk_window_get_skip_pager_hint (GtkWindow *window)
2595 {
2596 GtkWindowPrivate *priv;
2597
2598 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2599
2600 priv = GTK_WINDOW_GET_PRIVATE (window);
2601
2602 return priv->skips_pager;
2603 }
2604
2605 /**
2606 * gtk_window_set_urgency_hint:
2607 * @window: a #GtkWindow
2608 * @setting: %TRUE to mark this window as urgent
2609 *
2610 * Windows may set a hint asking the desktop environment to draw
2611 * the users attention to the window. This function sets this hint.
2612 *
2613 * Since: 2.8
2614 **/
2615 void
gtk_window_set_urgency_hint(GtkWindow * window,gboolean setting)2616 gtk_window_set_urgency_hint (GtkWindow *window,
2617 gboolean setting)
2618 {
2619 GtkWindowPrivate *priv;
2620
2621 g_return_if_fail (GTK_IS_WINDOW (window));
2622
2623 priv = GTK_WINDOW_GET_PRIVATE (window);
2624
2625 setting = setting != FALSE;
2626
2627 if (priv->urgent != setting)
2628 {
2629 priv->urgent = setting;
2630 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2631 gdk_window_set_urgency_hint (GTK_WIDGET (window)->window,
2632 priv->urgent);
2633 g_object_notify (G_OBJECT (window), "urgency-hint");
2634 }
2635 }
2636
2637 /**
2638 * gtk_window_get_urgency_hint:
2639 * @window: a #GtkWindow
2640 *
2641 * Gets the value set by gtk_window_set_urgency_hint()
2642 *
2643 * Return value: %TRUE if window is urgent
2644 *
2645 * Since: 2.8
2646 **/
2647 gboolean
gtk_window_get_urgency_hint(GtkWindow * window)2648 gtk_window_get_urgency_hint (GtkWindow *window)
2649 {
2650 GtkWindowPrivate *priv;
2651
2652 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2653
2654 priv = GTK_WINDOW_GET_PRIVATE (window);
2655
2656 return priv->urgent;
2657 }
2658
2659 /**
2660 * gtk_window_set_accept_focus:
2661 * @window: a #GtkWindow
2662 * @setting: %TRUE to let this window receive input focus
2663 *
2664 * Windows may set a hint asking the desktop environment not to receive
2665 * the input focus. This function sets this hint.
2666 *
2667 * Since: 2.4
2668 **/
2669 void
gtk_window_set_accept_focus(GtkWindow * window,gboolean setting)2670 gtk_window_set_accept_focus (GtkWindow *window,
2671 gboolean setting)
2672 {
2673 GtkWindowPrivate *priv;
2674
2675 g_return_if_fail (GTK_IS_WINDOW (window));
2676
2677 priv = GTK_WINDOW_GET_PRIVATE (window);
2678
2679 setting = setting != FALSE;
2680
2681 if (priv->accept_focus != setting)
2682 {
2683 priv->accept_focus = setting;
2684 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2685 gdk_window_set_accept_focus (GTK_WIDGET (window)->window,
2686 priv->accept_focus);
2687 g_object_notify (G_OBJECT (window), "accept-focus");
2688 }
2689 }
2690
2691 /**
2692 * gtk_window_get_accept_focus:
2693 * @window: a #GtkWindow
2694 *
2695 * Gets the value set by gtk_window_set_accept_focus().
2696 *
2697 * Return value: %TRUE if window should receive the input focus
2698 *
2699 * Since: 2.4
2700 **/
2701 gboolean
gtk_window_get_accept_focus(GtkWindow * window)2702 gtk_window_get_accept_focus (GtkWindow *window)
2703 {
2704 GtkWindowPrivate *priv;
2705
2706 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2707
2708 priv = GTK_WINDOW_GET_PRIVATE (window);
2709
2710 return priv->accept_focus;
2711 }
2712
2713 /**
2714 * gtk_window_set_focus_on_map:
2715 * @window: a #GtkWindow
2716 * @setting: %TRUE to let this window receive input focus on map
2717 *
2718 * Windows may set a hint asking the desktop environment not to receive
2719 * the input focus when the window is mapped. This function sets this
2720 * hint.
2721 *
2722 * Since: 2.6
2723 **/
2724 void
gtk_window_set_focus_on_map(GtkWindow * window,gboolean setting)2725 gtk_window_set_focus_on_map (GtkWindow *window,
2726 gboolean setting)
2727 {
2728 GtkWindowPrivate *priv;
2729
2730 g_return_if_fail (GTK_IS_WINDOW (window));
2731
2732 priv = GTK_WINDOW_GET_PRIVATE (window);
2733
2734 setting = setting != FALSE;
2735
2736 if (priv->focus_on_map != setting)
2737 {
2738 priv->focus_on_map = setting;
2739 if (gtk_widget_get_realized (GTK_WIDGET (window)))
2740 gdk_window_set_focus_on_map (GTK_WIDGET (window)->window,
2741 priv->focus_on_map);
2742 g_object_notify (G_OBJECT (window), "focus-on-map");
2743 }
2744 }
2745
2746 /**
2747 * gtk_window_get_focus_on_map:
2748 * @window: a #GtkWindow
2749 *
2750 * Gets the value set by gtk_window_set_focus_on_map().
2751 *
2752 * Return value: %TRUE if window should receive the input focus when
2753 * mapped.
2754 *
2755 * Since: 2.6
2756 **/
2757 gboolean
gtk_window_get_focus_on_map(GtkWindow * window)2758 gtk_window_get_focus_on_map (GtkWindow *window)
2759 {
2760 GtkWindowPrivate *priv;
2761
2762 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2763
2764 priv = GTK_WINDOW_GET_PRIVATE (window);
2765
2766 return priv->focus_on_map;
2767 }
2768
2769 /**
2770 * gtk_window_set_destroy_with_parent:
2771 * @window: a #GtkWindow
2772 * @setting: whether to destroy @window with its transient parent
2773 *
2774 * If @setting is %TRUE, then destroying the transient parent of @window
2775 * will also destroy @window itself. This is useful for dialogs that
2776 * shouldn't persist beyond the lifetime of the main window they're
2777 * associated with, for example.
2778 **/
2779 void
gtk_window_set_destroy_with_parent(GtkWindow * window,gboolean setting)2780 gtk_window_set_destroy_with_parent (GtkWindow *window,
2781 gboolean setting)
2782 {
2783 g_return_if_fail (GTK_IS_WINDOW (window));
2784
2785 if (window->destroy_with_parent == (setting != FALSE))
2786 return;
2787
2788 if (window->destroy_with_parent)
2789 {
2790 disconnect_parent_destroyed (window);
2791 }
2792 else
2793 {
2794 connect_parent_destroyed (window);
2795 }
2796
2797 window->destroy_with_parent = setting;
2798
2799 g_object_notify (G_OBJECT (window), "destroy-with-parent");
2800 }
2801
2802 /**
2803 * gtk_window_get_destroy_with_parent:
2804 * @window: a #GtkWindow
2805 *
2806 * Returns whether the window will be destroyed with its transient parent. See
2807 * gtk_window_set_destroy_with_parent ().
2808 *
2809 * Return value: %TRUE if the window will be destroyed with its transient parent.
2810 **/
2811 gboolean
gtk_window_get_destroy_with_parent(GtkWindow * window)2812 gtk_window_get_destroy_with_parent (GtkWindow *window)
2813 {
2814 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2815
2816 return window->destroy_with_parent;
2817 }
2818
2819 static GtkWindowGeometryInfo*
gtk_window_get_geometry_info(GtkWindow * window,gboolean create)2820 gtk_window_get_geometry_info (GtkWindow *window,
2821 gboolean create)
2822 {
2823 GtkWindowGeometryInfo *info;
2824
2825 info = window->geometry_info;
2826 if (!info && create)
2827 {
2828 info = g_new0 (GtkWindowGeometryInfo, 1);
2829
2830 info->default_width = -1;
2831 info->default_height = -1;
2832 info->resize_width = -1;
2833 info->resize_height = -1;
2834 info->initial_x = 0;
2835 info->initial_y = 0;
2836 info->initial_pos_set = FALSE;
2837 info->default_is_geometry = FALSE;
2838 info->position_constraints_changed = FALSE;
2839 info->last.configure_request.x = 0;
2840 info->last.configure_request.y = 0;
2841 info->last.configure_request.width = -1;
2842 info->last.configure_request.height = -1;
2843 info->widget = NULL;
2844 info->mask = 0;
2845 window->geometry_info = info;
2846 }
2847
2848 return info;
2849 }
2850
2851 /**
2852 * gtk_window_set_geometry_hints:
2853 * @window: a #GtkWindow
2854 * @geometry_widget: widget the geometry hints will be applied to
2855 * @geometry: struct containing geometry information
2856 * @geom_mask: mask indicating which struct fields should be paid attention to
2857 *
2858 * This function sets up hints about how a window can be resized by
2859 * the user. You can set a minimum and maximum size; allowed resize
2860 * increments (e.g. for xterm, you can only resize by the size of a
2861 * character); aspect ratios; and more. See the #GdkGeometry struct.
2862 *
2863 **/
2864 void
gtk_window_set_geometry_hints(GtkWindow * window,GtkWidget * geometry_widget,GdkGeometry * geometry,GdkWindowHints geom_mask)2865 gtk_window_set_geometry_hints (GtkWindow *window,
2866 GtkWidget *geometry_widget,
2867 GdkGeometry *geometry,
2868 GdkWindowHints geom_mask)
2869 {
2870 GtkWindowGeometryInfo *info;
2871
2872 g_return_if_fail (GTK_IS_WINDOW (window));
2873 g_return_if_fail (geometry_widget == NULL || GTK_IS_WIDGET (geometry_widget));
2874
2875 info = gtk_window_get_geometry_info (window, TRUE);
2876
2877 if (info->widget)
2878 g_signal_handlers_disconnect_by_func (info->widget,
2879 gtk_widget_destroyed,
2880 &info->widget);
2881
2882 info->widget = geometry_widget;
2883 if (info->widget)
2884 g_signal_connect (geometry_widget, "destroy",
2885 G_CALLBACK (gtk_widget_destroyed),
2886 &info->widget);
2887
2888 if (geometry)
2889 info->geometry = *geometry;
2890
2891 /* We store gravity in window->gravity not in the hints. */
2892 info->mask = geom_mask & ~(GDK_HINT_WIN_GRAVITY);
2893
2894 if (geom_mask & GDK_HINT_WIN_GRAVITY)
2895 {
2896 gtk_window_set_gravity (window, geometry->win_gravity);
2897 }
2898
2899 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
2900 }
2901
2902 /**
2903 * gtk_window_set_decorated:
2904 * @window: a #GtkWindow
2905 * @setting: %TRUE to decorate the window
2906 *
2907 * By default, windows are decorated with a title bar, resize
2908 * controls, etc. Some <link linkend="gtk-X11-arch">window
2909 * managers</link> allow GTK+ to disable these decorations, creating a
2910 * borderless window. If you set the decorated property to %FALSE
2911 * using this function, GTK+ will do its best to convince the window
2912 * manager not to decorate the window. Depending on the system, this
2913 * function may not have any effect when called on a window that is
2914 * already visible, so you should call it before calling gtk_window_show().
2915 *
2916 * On Windows, this function always works, since there's no window manager
2917 * policy involved.
2918 *
2919 **/
2920 void
gtk_window_set_decorated(GtkWindow * window,gboolean setting)2921 gtk_window_set_decorated (GtkWindow *window,
2922 gboolean setting)
2923 {
2924 g_return_if_fail (GTK_IS_WINDOW (window));
2925
2926 setting = setting != FALSE;
2927
2928 if (setting == window->decorated)
2929 return;
2930
2931 window->decorated = setting;
2932
2933 if (GTK_WIDGET (window)->window)
2934 {
2935 if (window->decorated)
2936 gdk_window_set_decorations (GTK_WIDGET (window)->window,
2937 GDK_DECOR_ALL);
2938 else
2939 gdk_window_set_decorations (GTK_WIDGET (window)->window,
2940 0);
2941 }
2942
2943 g_object_notify (G_OBJECT (window), "decorated");
2944 }
2945
2946 /**
2947 * gtk_window_get_decorated:
2948 * @window: a #GtkWindow
2949 *
2950 * Returns whether the window has been set to have decorations
2951 * such as a title bar via gtk_window_set_decorated().
2952 *
2953 * Return value: %TRUE if the window has been set to have decorations
2954 **/
2955 gboolean
gtk_window_get_decorated(GtkWindow * window)2956 gtk_window_get_decorated (GtkWindow *window)
2957 {
2958 g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
2959
2960 return window->decorated;
2961 }
2962
2963 /**
2964 * gtk_window_set_deletable:
2965 * @window: a #GtkWindow
2966 * @setting: %TRUE to decorate the window as deletable
2967 *
2968 * By default, windows have a close button in the window frame. Some
2969 * <link linkend="gtk-X11-arch">window managers</link> allow GTK+ to
2970 * disable this button. If you set the deletable property to %FALSE
2971 * using this function, GTK+ will do its best to convince the window
2972 * manager not to show a close button. Depending on the system, this
2973 * function may not have any effect when called on a window that is
2974 * already visible, so you should call it before calling gtk_window_show().
2975 *
2976 * On Windows, this function always works, since there's no window manager
2977 * policy involved.
2978 *
2979 * Since: 2.10
2980 */
2981 void
gtk_window_set_deletable(GtkWindow * window,gboolean setting)2982 gtk_window_set_deletable (GtkWindow *window,
2983 gboolean setting)
2984 {
2985 GtkWindowPrivate *priv;
2986
2987 g_return_if_fail (GTK_IS_WINDOW (window));
2988
2989 priv = GTK_WINDOW_GET_PRIVATE (window);
2990
2991 setting = setting != FALSE;
2992
2993 if (setting == priv->deletable)
2994 return;
2995
2996 priv->deletable = setting;
2997
2998 if (GTK_WIDGET (window)->window)
2999 {
3000 if (priv->deletable)
3001 gdk_window_set_functions (GTK_WIDGET (window)->window,
3002 GDK_FUNC_ALL);
3003 else
3004 gdk_window_set_functions (GTK_WIDGET (window)->window,
3005 GDK_FUNC_ALL | GDK_FUNC_CLOSE);
3006 }
3007
3008 g_object_notify (G_OBJECT (window), "deletable");
3009 }
3010
3011 /**
3012 * gtk_window_get_deletable:
3013 * @window: a #GtkWindow
3014 *
3015 * Returns whether the window has been set to have a close button
3016 * via gtk_window_set_deletable().
3017 *
3018 * Return value: %TRUE if the window has been set to have a close button
3019 *
3020 * Since: 2.10
3021 **/
3022 gboolean
gtk_window_get_deletable(GtkWindow * window)3023 gtk_window_get_deletable (GtkWindow *window)
3024 {
3025 GtkWindowPrivate *priv;
3026
3027 g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
3028
3029 priv = GTK_WINDOW_GET_PRIVATE (window);
3030
3031 return priv->deletable;
3032 }
3033
3034 static GtkWindowIconInfo*
get_icon_info(GtkWindow * window)3035 get_icon_info (GtkWindow *window)
3036 {
3037 return g_object_get_qdata (G_OBJECT (window), quark_gtk_window_icon_info);
3038 }
3039
3040 static void
free_icon_info(GtkWindowIconInfo * info)3041 free_icon_info (GtkWindowIconInfo *info)
3042 {
3043 g_free (info->icon_name);
3044 g_slice_free (GtkWindowIconInfo, info);
3045 }
3046
3047
3048 static GtkWindowIconInfo*
ensure_icon_info(GtkWindow * window)3049 ensure_icon_info (GtkWindow *window)
3050 {
3051 GtkWindowIconInfo *info;
3052
3053 info = get_icon_info (window);
3054
3055 if (info == NULL)
3056 {
3057 info = g_slice_new0 (GtkWindowIconInfo);
3058 g_object_set_qdata_full (G_OBJECT (window),
3059 quark_gtk_window_icon_info,
3060 info,
3061 (GDestroyNotify)free_icon_info);
3062 }
3063
3064 return info;
3065 }
3066
3067 typedef struct {
3068 guint serial;
3069 GdkPixmap *pixmap;
3070 GdkPixmap *mask;
3071 } ScreenIconInfo;
3072
3073 static ScreenIconInfo *
get_screen_icon_info(GdkScreen * screen)3074 get_screen_icon_info (GdkScreen *screen)
3075 {
3076 ScreenIconInfo *info = g_object_get_qdata (G_OBJECT (screen),
3077 quark_gtk_window_default_icon_pixmap);
3078 if (!info)
3079 {
3080 info = g_slice_new0 (ScreenIconInfo);
3081 g_object_set_qdata (G_OBJECT (screen),
3082 quark_gtk_window_default_icon_pixmap, info);
3083 }
3084
3085 if (info->serial != default_icon_serial)
3086 {
3087 if (info->pixmap)
3088 {
3089 g_object_remove_weak_pointer (G_OBJECT (info->pixmap), (gpointer*)&info->pixmap);
3090 info->pixmap = NULL;
3091 }
3092
3093 if (info->mask)
3094 {
3095 g_object_remove_weak_pointer (G_OBJECT (info->mask), (gpointer*)&info->mask);
3096 info->mask = NULL;
3097 }
3098
3099 info->serial = default_icon_serial;
3100 }
3101
3102 return info;
3103 }
3104
3105 static void
get_pixmap_and_mask(GdkWindow * window,GtkWindowIconInfo * parent_info,gboolean is_default_list,GList * icon_list,GdkPixmap ** pmap_return,GdkBitmap ** mask_return)3106 get_pixmap_and_mask (GdkWindow *window,
3107 GtkWindowIconInfo *parent_info,
3108 gboolean is_default_list,
3109 GList *icon_list,
3110 GdkPixmap **pmap_return,
3111 GdkBitmap **mask_return)
3112 {
3113 GdkScreen *screen = gdk_window_get_screen (window);
3114 ScreenIconInfo *default_icon_info = get_screen_icon_info (screen);
3115 GdkPixbuf *best_icon;
3116 GList *tmp_list;
3117 int best_size;
3118
3119 *pmap_return = NULL;
3120 *mask_return = NULL;
3121
3122 if (is_default_list &&
3123 default_icon_info->pixmap != NULL)
3124 {
3125 /* Use shared icon pixmap for all windows on this screen.
3126 */
3127 if (default_icon_info->pixmap)
3128 g_object_ref (default_icon_info->pixmap);
3129 if (default_icon_info->mask)
3130 g_object_ref (default_icon_info->mask);
3131
3132 *pmap_return = default_icon_info->pixmap;
3133 *mask_return = default_icon_info->mask;
3134 }
3135 else if (parent_info && parent_info->icon_pixmap)
3136 {
3137 if (parent_info->icon_pixmap)
3138 g_object_ref (parent_info->icon_pixmap);
3139 if (parent_info->icon_mask)
3140 g_object_ref (parent_info->icon_mask);
3141
3142 *pmap_return = parent_info->icon_pixmap;
3143 *mask_return = parent_info->icon_mask;
3144 }
3145 else
3146 {
3147 #define IDEAL_SIZE 48
3148
3149 best_size = G_MAXINT;
3150 best_icon = NULL;
3151 tmp_list = icon_list;
3152 while (tmp_list != NULL)
3153 {
3154 GdkPixbuf *pixbuf = tmp_list->data;
3155 int this;
3156
3157 /* average width and height - if someone passes in a rectangular
3158 * icon they deserve what they get.
3159 */
3160 this = gdk_pixbuf_get_width (pixbuf) + gdk_pixbuf_get_height (pixbuf);
3161 this /= 2;
3162
3163 if (best_icon == NULL)
3164 {
3165 best_icon = pixbuf;
3166 best_size = this;
3167 }
3168 else
3169 {
3170 /* icon is better if it's 32 pixels or larger, and closer to
3171 * the ideal size than the current best.
3172 */
3173 if (this >= 32 &&
3174 (ABS (best_size - IDEAL_SIZE) <
3175 ABS (this - IDEAL_SIZE)))
3176 {
3177 best_icon = pixbuf;
3178 best_size = this;
3179 }
3180 }
3181
3182 tmp_list = tmp_list->next;
3183 }
3184
3185 if (best_icon)
3186 gdk_pixbuf_render_pixmap_and_mask_for_colormap (best_icon,
3187 gdk_screen_get_system_colormap (screen),
3188 pmap_return,
3189 mask_return,
3190 128);
3191
3192 /* Save pmap/mask for others to use if appropriate */
3193 if (parent_info)
3194 {
3195 parent_info->icon_pixmap = *pmap_return;
3196 parent_info->icon_mask = *mask_return;
3197
3198 if (parent_info->icon_pixmap)
3199 g_object_ref (parent_info->icon_pixmap);
3200 if (parent_info->icon_mask)
3201 g_object_ref (parent_info->icon_mask);
3202 }
3203 else if (is_default_list)
3204 {
3205 default_icon_info->pixmap = *pmap_return;
3206 default_icon_info->mask = *mask_return;
3207
3208 if (default_icon_info->pixmap)
3209 g_object_add_weak_pointer (G_OBJECT (default_icon_info->pixmap),
3210 (gpointer*)&default_icon_info->pixmap);
3211 if (default_icon_info->mask)
3212 g_object_add_weak_pointer (G_OBJECT (default_icon_info->mask),
3213 (gpointer*)&default_icon_info->mask);
3214 }
3215 }
3216 }
3217
3218 static GList *
icon_list_from_theme(GtkWidget * widget,const gchar * name)3219 icon_list_from_theme (GtkWidget *widget,
3220 const gchar *name)
3221 {
3222 GList *list;
3223
3224 GtkIconTheme *icon_theme;
3225 GdkPixbuf *icon;
3226 gint *sizes;
3227 gint i;
3228
3229 icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
3230
3231 sizes = gtk_icon_theme_get_icon_sizes (icon_theme, name);
3232
3233 list = NULL;
3234 for (i = 0; sizes[i]; i++)
3235 {
3236 /* FIXME
3237 * We need an EWMH extension to handle scalable icons
3238 * by passing their name to the WM. For now just use a
3239 * fixed size of 48.
3240 */
3241 if (sizes[i] == -1)
3242 icon = gtk_icon_theme_load_icon (icon_theme, name,
3243 48, 0, NULL);
3244 else
3245 icon = gtk_icon_theme_load_icon (icon_theme, name,
3246 sizes[i], 0, NULL);
3247 if (icon)
3248 list = g_list_append (list, icon);
3249 }
3250
3251 g_free (sizes);
3252
3253 return list;
3254 }
3255
3256
3257 static void
gtk_window_realize_icon(GtkWindow * window)3258 gtk_window_realize_icon (GtkWindow *window)
3259 {
3260 GtkWidget *widget;
3261 GtkWindowIconInfo *info;
3262 GList *icon_list;
3263
3264 widget = GTK_WIDGET (window);
3265
3266 g_return_if_fail (widget->window != NULL);
3267
3268 /* no point setting an icon on override-redirect */
3269 if (window->type == GTK_WINDOW_POPUP)
3270 return;
3271
3272 icon_list = NULL;
3273
3274 info = ensure_icon_info (window);
3275
3276 if (info->realized)
3277 return;
3278
3279 g_return_if_fail (info->icon_pixmap == NULL);
3280 g_return_if_fail (info->icon_mask == NULL);
3281
3282 info->using_default_icon = FALSE;
3283 info->using_parent_icon = FALSE;
3284 info->using_themed_icon = FALSE;
3285
3286 icon_list = info->icon_list;
3287
3288 /* Look up themed icon */
3289 if (icon_list == NULL && info->icon_name)
3290 {
3291 icon_list = icon_list_from_theme (widget, info->icon_name);
3292 if (icon_list)
3293 info->using_themed_icon = TRUE;
3294 }
3295
3296 /* Inherit from transient parent */
3297 if (icon_list == NULL && window->transient_parent)
3298 {
3299 icon_list = ensure_icon_info (window->transient_parent)->icon_list;
3300 if (icon_list)
3301 info->using_parent_icon = TRUE;
3302 }
3303
3304 /* Inherit from default */
3305 if (icon_list == NULL)
3306 {
3307 icon_list = default_icon_list;
3308 if (icon_list)
3309 info->using_default_icon = TRUE;
3310 }
3311
3312 /* Look up themed icon */
3313 if (icon_list == NULL && default_icon_name)
3314 {
3315 icon_list = icon_list_from_theme (widget, default_icon_name);
3316 info->using_default_icon = TRUE;
3317 info->using_themed_icon = TRUE;
3318 }
3319
3320 gdk_window_set_icon_list (widget->window, icon_list);
3321
3322 get_pixmap_and_mask (widget->window,
3323 info->using_parent_icon ? ensure_icon_info (window->transient_parent) : NULL,
3324 info->using_default_icon,
3325 icon_list,
3326 &info->icon_pixmap,
3327 &info->icon_mask);
3328
3329 /* This is a slight ICCCM violation since it's a color pixmap not
3330 * a bitmap, but everyone does it.
3331 */
3332 gdk_window_set_icon (widget->window,
3333 NULL,
3334 info->icon_pixmap,
3335 info->icon_mask);
3336
3337 info->realized = TRUE;
3338
3339 if (info->using_themed_icon)
3340 {
3341 GtkIconTheme *icon_theme;
3342
3343 g_list_foreach (icon_list, (GFunc) g_object_unref, NULL);
3344 g_list_free (icon_list);
3345
3346 icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
3347 g_signal_connect (icon_theme, "changed",
3348 G_CALLBACK (update_themed_icon), window);
3349 }
3350 }
3351
3352 static void
gtk_window_unrealize_icon(GtkWindow * window)3353 gtk_window_unrealize_icon (GtkWindow *window)
3354 {
3355 GtkWindowIconInfo *info;
3356
3357 info = get_icon_info (window);
3358
3359 if (info == NULL)
3360 return;
3361
3362 if (info->icon_pixmap)
3363 g_object_unref (info->icon_pixmap);
3364
3365 if (info->icon_mask)
3366 g_object_unref (info->icon_mask);
3367
3368 info->icon_pixmap = NULL;
3369 info->icon_mask = NULL;
3370
3371 if (info->using_themed_icon)
3372 {
3373 GtkIconTheme *icon_theme;
3374
3375 icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
3376
3377 g_signal_handlers_disconnect_by_func (icon_theme, update_themed_icon, window);
3378 }
3379
3380 /* We don't clear the properties on the window, just figure the
3381 * window is going away.
3382 */
3383
3384 info->realized = FALSE;
3385
3386 }
3387
3388 /**
3389 * gtk_window_set_icon_list:
3390 * @window: a #GtkWindow
3391 * @list: list of #GdkPixbuf
3392 *
3393 * Sets up the icon representing a #GtkWindow. The icon is used when
3394 * the window is minimized (also known as iconified). Some window
3395 * managers or desktop environments may also place it in the window
3396 * frame, or display it in other contexts.
3397 *
3398 * gtk_window_set_icon_list() allows you to pass in the same icon in
3399 * several hand-drawn sizes. The list should contain the natural sizes
3400 * your icon is available in; that is, don't scale the image before
3401 * passing it to GTK+. Scaling is postponed until the last minute,
3402 * when the desired final size is known, to allow best quality.
3403 *
3404 * By passing several sizes, you may improve the final image quality
3405 * of the icon, by reducing or eliminating automatic image scaling.
3406 *
3407 * Recommended sizes to provide: 16x16, 32x32, 48x48 at minimum, and
3408 * larger images (64x64, 128x128) if you have them.
3409 *
3410 * See also gtk_window_set_default_icon_list() to set the icon
3411 * for all windows in your application in one go.
3412 *
3413 * Note that transient windows (those who have been set transient for another
3414 * window using gtk_window_set_transient_for()) will inherit their
3415 * icon from their transient parent. So there's no need to explicitly
3416 * set the icon on transient windows.
3417 **/
3418 void
gtk_window_set_icon_list(GtkWindow * window,GList * list)3419 gtk_window_set_icon_list (GtkWindow *window,
3420 GList *list)
3421 {
3422 GtkWindowIconInfo *info;
3423
3424 g_return_if_fail (GTK_IS_WINDOW (window));
3425
3426 info = ensure_icon_info (window);
3427
3428 if (info->icon_list == list) /* check for NULL mostly */
3429 return;
3430
3431 g_list_foreach (list,
3432 (GFunc) g_object_ref, NULL);
3433
3434 g_list_foreach (info->icon_list,
3435 (GFunc) g_object_unref, NULL);
3436
3437 g_list_free (info->icon_list);
3438
3439 info->icon_list = g_list_copy (list);
3440
3441 g_object_notify (G_OBJECT (window), "icon");
3442
3443 gtk_window_unrealize_icon (window);
3444
3445 if (gtk_widget_get_realized (GTK_WIDGET (window)))
3446 gtk_window_realize_icon (window);
3447
3448 /* We could try to update our transient children, but I don't think
3449 * it's really worth it. If we did it, the best way would probably
3450 * be to have children connect to notify::icon-list
3451 */
3452 }
3453
3454 /**
3455 * gtk_window_get_icon_list:
3456 * @window: a #GtkWindow
3457 *
3458 * Retrieves the list of icons set by gtk_window_set_icon_list().
3459 * The list is copied, but the reference count on each
3460 * member won't be incremented.
3461 *
3462 * Return value: (element-type GdkPixbuf) (transfer container): copy of window's icon list
3463 **/
3464 GList*
gtk_window_get_icon_list(GtkWindow * window)3465 gtk_window_get_icon_list (GtkWindow *window)
3466 {
3467 GtkWindowIconInfo *info;
3468
3469 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3470
3471 info = get_icon_info (window);
3472
3473 if (info)
3474 return g_list_copy (info->icon_list);
3475 else
3476 return NULL;
3477 }
3478
3479 /**
3480 * gtk_window_set_icon:
3481 * @window: a #GtkWindow
3482 * @icon: (allow-none): icon image, or %NULL
3483 *
3484 * Sets up the icon representing a #GtkWindow. This icon is used when
3485 * the window is minimized (also known as iconified). Some window
3486 * managers or desktop environments may also place it in the window
3487 * frame, or display it in other contexts.
3488 *
3489 * The icon should be provided in whatever size it was naturally
3490 * drawn; that is, don't scale the image before passing it to
3491 * GTK+. Scaling is postponed until the last minute, when the desired
3492 * final size is known, to allow best quality.
3493 *
3494 * If you have your icon hand-drawn in multiple sizes, use
3495 * gtk_window_set_icon_list(). Then the best size will be used.
3496 *
3497 * This function is equivalent to calling gtk_window_set_icon_list()
3498 * with a 1-element list.
3499 *
3500 * See also gtk_window_set_default_icon_list() to set the icon
3501 * for all windows in your application in one go.
3502 **/
3503 void
gtk_window_set_icon(GtkWindow * window,GdkPixbuf * icon)3504 gtk_window_set_icon (GtkWindow *window,
3505 GdkPixbuf *icon)
3506 {
3507 GList *list;
3508
3509 g_return_if_fail (GTK_IS_WINDOW (window));
3510 g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon));
3511
3512 list = NULL;
3513
3514 if (icon)
3515 list = g_list_append (list, icon);
3516
3517 gtk_window_set_icon_list (window, list);
3518 g_list_free (list);
3519 }
3520
3521
3522 static void
update_themed_icon(GtkIconTheme * icon_theme,GtkWindow * window)3523 update_themed_icon (GtkIconTheme *icon_theme,
3524 GtkWindow *window)
3525 {
3526 g_object_notify (G_OBJECT (window), "icon");
3527
3528 gtk_window_unrealize_icon (window);
3529
3530 if (gtk_widget_get_realized (GTK_WIDGET (window)))
3531 gtk_window_realize_icon (window);
3532 }
3533
3534 /**
3535 * gtk_window_set_icon_name:
3536 * @window: a #GtkWindow
3537 * @name: (allow-none): the name of the themed icon
3538 *
3539 * Sets the icon for the window from a named themed icon. See
3540 * the docs for #GtkIconTheme for more details.
3541 *
3542 * Note that this has nothing to do with the WM_ICON_NAME
3543 * property which is mentioned in the ICCCM.
3544 *
3545 * Since: 2.6
3546 */
3547 void
gtk_window_set_icon_name(GtkWindow * window,const gchar * name)3548 gtk_window_set_icon_name (GtkWindow *window,
3549 const gchar *name)
3550 {
3551 GtkWindowIconInfo *info;
3552 gchar *tmp;
3553
3554 g_return_if_fail (GTK_IS_WINDOW (window));
3555
3556 info = ensure_icon_info (window);
3557
3558 if (g_strcmp0 (info->icon_name, name) == 0)
3559 return;
3560
3561 tmp = info->icon_name;
3562 info->icon_name = g_strdup (name);
3563 g_free (tmp);
3564
3565 g_list_foreach (info->icon_list, (GFunc) g_object_unref, NULL);
3566 g_list_free (info->icon_list);
3567 info->icon_list = NULL;
3568
3569 update_themed_icon (NULL, window);
3570
3571 g_object_notify (G_OBJECT (window), "icon-name");
3572 }
3573
3574 /**
3575 * gtk_window_get_icon_name:
3576 * @window: a #GtkWindow
3577 *
3578 * Returns the name of the themed icon for the window,
3579 * see gtk_window_set_icon_name().
3580 *
3581 * Returns: the icon name or %NULL if the window has
3582 * no themed icon
3583 *
3584 * Since: 2.6
3585 */
3586 const gchar *
gtk_window_get_icon_name(GtkWindow * window)3587 gtk_window_get_icon_name (GtkWindow *window)
3588 {
3589 GtkWindowIconInfo *info;
3590
3591 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3592
3593 info = ensure_icon_info (window);
3594
3595 return info->icon_name;
3596 }
3597
3598 /**
3599 * gtk_window_get_icon:
3600 * @window: a #GtkWindow
3601 *
3602 * Gets the value set by gtk_window_set_icon() (or if you've
3603 * called gtk_window_set_icon_list(), gets the first icon in
3604 * the icon list).
3605 *
3606 * Return value: (transfer none): icon for window
3607 **/
3608 GdkPixbuf*
gtk_window_get_icon(GtkWindow * window)3609 gtk_window_get_icon (GtkWindow *window)
3610 {
3611 GtkWindowIconInfo *info;
3612
3613 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3614
3615 info = get_icon_info (window);
3616 if (info && info->icon_list)
3617 return GDK_PIXBUF (info->icon_list->data);
3618 else
3619 return NULL;
3620 }
3621
3622 /* Load pixbuf, printing warning on failure if error == NULL
3623 */
3624 static GdkPixbuf *
load_pixbuf_verbosely(const char * filename,GError ** err)3625 load_pixbuf_verbosely (const char *filename,
3626 GError **err)
3627 {
3628 GError *local_err = NULL;
3629 GdkPixbuf *pixbuf;
3630
3631 pixbuf = gdk_pixbuf_new_from_file (filename, &local_err);
3632
3633 if (!pixbuf)
3634 {
3635 if (err)
3636 *err = local_err;
3637 else
3638 {
3639 g_warning ("Error loading icon from file '%s':\n\t%s",
3640 filename, local_err->message);
3641 g_error_free (local_err);
3642 }
3643 }
3644
3645 return pixbuf;
3646 }
3647
3648 /**
3649 * gtk_window_set_icon_from_file:
3650 * @window: a #GtkWindow
3651 * @filename: location of icon file
3652 * @err: (allow-none): location to store error, or %NULL.
3653 *
3654 * Sets the icon for @window.
3655 * Warns on failure if @err is %NULL.
3656 *
3657 * This function is equivalent to calling gtk_window_set_icon()
3658 * with a pixbuf created by loading the image from @filename.
3659 *
3660 * Returns: %TRUE if setting the icon succeeded.
3661 *
3662 * Since: 2.2
3663 **/
3664 gboolean
gtk_window_set_icon_from_file(GtkWindow * window,const gchar * filename,GError ** err)3665 gtk_window_set_icon_from_file (GtkWindow *window,
3666 const gchar *filename,
3667 GError **err)
3668 {
3669 GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
3670
3671 if (pixbuf)
3672 {
3673 gtk_window_set_icon (window, pixbuf);
3674 g_object_unref (pixbuf);
3675
3676 return TRUE;
3677 }
3678 else
3679 return FALSE;
3680 }
3681
3682 /**
3683 * gtk_window_set_default_icon_list:
3684 * @list: (element-type GdkPixbuf) (transfer container): a list of #GdkPixbuf
3685 *
3686 * Sets an icon list to be used as fallback for windows that haven't
3687 * had gtk_window_set_icon_list() called on them to set up a
3688 * window-specific icon list. This function allows you to set up the
3689 * icon for all windows in your app at once.
3690 *
3691 * See gtk_window_set_icon_list() for more details.
3692 *
3693 **/
3694 void
gtk_window_set_default_icon_list(GList * list)3695 gtk_window_set_default_icon_list (GList *list)
3696 {
3697 GList *toplevels;
3698 GList *tmp_list;
3699 if (list == default_icon_list)
3700 return;
3701
3702 /* Update serial so we don't used cached pixmaps/masks
3703 */
3704 default_icon_serial++;
3705
3706 g_list_foreach (list,
3707 (GFunc) g_object_ref, NULL);
3708
3709 g_list_foreach (default_icon_list,
3710 (GFunc) g_object_unref, NULL);
3711
3712 g_list_free (default_icon_list);
3713
3714 default_icon_list = g_list_copy (list);
3715
3716 /* Update all toplevels */
3717 toplevels = gtk_window_list_toplevels ();
3718 tmp_list = toplevels;
3719 while (tmp_list != NULL)
3720 {
3721 GtkWindowIconInfo *info;
3722 GtkWindow *w = tmp_list->data;
3723
3724 info = get_icon_info (w);
3725 if (info && info->using_default_icon)
3726 {
3727 gtk_window_unrealize_icon (w);
3728 if (gtk_widget_get_realized (GTK_WIDGET (w)))
3729 gtk_window_realize_icon (w);
3730 }
3731
3732 tmp_list = tmp_list->next;
3733 }
3734 g_list_free (toplevels);
3735 }
3736
3737 /**
3738 * gtk_window_set_default_icon:
3739 * @icon: the icon
3740 *
3741 * Sets an icon to be used as fallback for windows that haven't
3742 * had gtk_window_set_icon() called on them from a pixbuf.
3743 *
3744 * Since: 2.4
3745 **/
3746 void
gtk_window_set_default_icon(GdkPixbuf * icon)3747 gtk_window_set_default_icon (GdkPixbuf *icon)
3748 {
3749 GList *list;
3750
3751 g_return_if_fail (GDK_IS_PIXBUF (icon));
3752
3753 list = g_list_prepend (NULL, icon);
3754 gtk_window_set_default_icon_list (list);
3755 g_list_free (list);
3756 }
3757
3758 /**
3759 * gtk_window_set_default_icon_name:
3760 * @name: the name of the themed icon
3761 *
3762 * Sets an icon to be used as fallback for windows that haven't
3763 * had gtk_window_set_icon_list() called on them from a named
3764 * themed icon, see gtk_window_set_icon_name().
3765 *
3766 * Since: 2.6
3767 **/
3768 void
gtk_window_set_default_icon_name(const gchar * name)3769 gtk_window_set_default_icon_name (const gchar *name)
3770 {
3771 GList *tmp_list;
3772 GList *toplevels;
3773
3774 /* Update serial so we don't used cached pixmaps/masks
3775 */
3776 default_icon_serial++;
3777
3778 g_free (default_icon_name);
3779 default_icon_name = g_strdup (name);
3780
3781 g_list_foreach (default_icon_list,
3782 (GFunc) g_object_unref, NULL);
3783
3784 g_list_free (default_icon_list);
3785 default_icon_list = NULL;
3786
3787 /* Update all toplevels */
3788 toplevels = gtk_window_list_toplevels ();
3789 tmp_list = toplevels;
3790 while (tmp_list != NULL)
3791 {
3792 GtkWindowIconInfo *info;
3793 GtkWindow *w = tmp_list->data;
3794
3795 info = get_icon_info (w);
3796 if (info && info->using_default_icon && info->using_themed_icon)
3797 {
3798 gtk_window_unrealize_icon (w);
3799 if (gtk_widget_get_realized (GTK_WIDGET (w)))
3800 gtk_window_realize_icon (w);
3801 }
3802
3803 tmp_list = tmp_list->next;
3804 }
3805 g_list_free (toplevels);
3806 }
3807
3808 /**
3809 * gtk_window_get_default_icon_name:
3810 *
3811 * Returns the fallback icon name for windows that has been set
3812 * with gtk_window_set_default_icon_name(). The returned
3813 * string is owned by GTK+ and should not be modified. It
3814 * is only valid until the next call to
3815 * gtk_window_set_default_icon_name().
3816 *
3817 * Returns: the fallback icon name for windows
3818 *
3819 * Since: 2.16
3820 */
3821 const gchar *
gtk_window_get_default_icon_name(void)3822 gtk_window_get_default_icon_name (void)
3823 {
3824 return default_icon_name;
3825 }
3826
3827 /**
3828 * gtk_window_set_default_icon_from_file:
3829 * @filename: location of icon file
3830 * @err: (allow-none): location to store error, or %NULL.
3831 *
3832 * Sets an icon to be used as fallback for windows that haven't
3833 * had gtk_window_set_icon_list() called on them from a file
3834 * on disk. Warns on failure if @err is %NULL.
3835 *
3836 * Returns: %TRUE if setting the icon succeeded.
3837 *
3838 * Since: 2.2
3839 **/
3840 gboolean
gtk_window_set_default_icon_from_file(const gchar * filename,GError ** err)3841 gtk_window_set_default_icon_from_file (const gchar *filename,
3842 GError **err)
3843 {
3844 GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
3845
3846 if (pixbuf)
3847 {
3848 gtk_window_set_default_icon (pixbuf);
3849 g_object_unref (pixbuf);
3850
3851 return TRUE;
3852 }
3853 else
3854 return FALSE;
3855 }
3856
3857 /**
3858 * gtk_window_get_default_icon_list:
3859 *
3860 * Gets the value set by gtk_window_set_default_icon_list().
3861 * The list is a copy and should be freed with g_list_free(),
3862 * but the pixbufs in the list have not had their reference count
3863 * incremented.
3864 *
3865 * Return value: (element-type GdkPixbuf) (transfer container): copy of default icon list
3866 **/
3867 GList*
gtk_window_get_default_icon_list(void)3868 gtk_window_get_default_icon_list (void)
3869 {
3870 return g_list_copy (default_icon_list);
3871 }
3872
3873 static void
gtk_window_set_default_size_internal(GtkWindow * window,gboolean change_width,gint width,gboolean change_height,gint height,gboolean is_geometry)3874 gtk_window_set_default_size_internal (GtkWindow *window,
3875 gboolean change_width,
3876 gint width,
3877 gboolean change_height,
3878 gint height,
3879 gboolean is_geometry)
3880 {
3881 GtkWindowGeometryInfo *info;
3882
3883 g_return_if_fail (change_width == FALSE || width >= -1);
3884 g_return_if_fail (change_height == FALSE || height >= -1);
3885
3886 info = gtk_window_get_geometry_info (window, TRUE);
3887
3888 g_object_freeze_notify (G_OBJECT (window));
3889
3890 info->default_is_geometry = is_geometry != FALSE;
3891
3892 if (change_width)
3893 {
3894 if (width == 0)
3895 width = 1;
3896
3897 if (width < 0)
3898 width = -1;
3899
3900 info->default_width = width;
3901
3902 g_object_notify (G_OBJECT (window), "default-width");
3903 }
3904
3905 if (change_height)
3906 {
3907 if (height == 0)
3908 height = 1;
3909
3910 if (height < 0)
3911 height = -1;
3912
3913 info->default_height = height;
3914
3915 g_object_notify (G_OBJECT (window), "default-height");
3916 }
3917
3918 g_object_thaw_notify (G_OBJECT (window));
3919
3920 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
3921 }
3922
3923 /**
3924 * gtk_window_set_default_size:
3925 * @window: a #GtkWindow
3926 * @width: width in pixels, or -1 to unset the default width
3927 * @height: height in pixels, or -1 to unset the default height
3928 *
3929 * Sets the default size of a window. If the window's "natural" size
3930 * (its size request) is larger than the default, the default will be
3931 * ignored. More generally, if the default size does not obey the
3932 * geometry hints for the window (gtk_window_set_geometry_hints() can
3933 * be used to set these explicitly), the default size will be clamped
3934 * to the nearest permitted size.
3935 *
3936 * Unlike gtk_widget_set_size_request(), which sets a size request for
3937 * a widget and thus would keep users from shrinking the window, this
3938 * function only sets the initial size, just as if the user had
3939 * resized the window themselves. Users can still shrink the window
3940 * again as they normally would. Setting a default size of -1 means to
3941 * use the "natural" default size (the size request of the window).
3942 *
3943 * For more control over a window's initial size and how resizing works,
3944 * investigate gtk_window_set_geometry_hints().
3945 *
3946 * For some uses, gtk_window_resize() is a more appropriate function.
3947 * gtk_window_resize() changes the current size of the window, rather
3948 * than the size to be used on initial display. gtk_window_resize() always
3949 * affects the window itself, not the geometry widget.
3950 *
3951 * The default size of a window only affects the first time a window is
3952 * shown; if a window is hidden and re-shown, it will remember the size
3953 * it had prior to hiding, rather than using the default size.
3954 *
3955 * Windows can't actually be 0x0 in size, they must be at least 1x1, but
3956 * passing 0 for @width and @height is OK, resulting in a 1x1 default size.
3957 **/
3958 void
gtk_window_set_default_size(GtkWindow * window,gint width,gint height)3959 gtk_window_set_default_size (GtkWindow *window,
3960 gint width,
3961 gint height)
3962 {
3963 g_return_if_fail (GTK_IS_WINDOW (window));
3964 g_return_if_fail (width >= -1);
3965 g_return_if_fail (height >= -1);
3966
3967 gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE);
3968 }
3969
3970 /**
3971 * gtk_window_get_default_size:
3972 * @window: a #GtkWindow
3973 * @width: (allow-none): location to store the default width, or %NULL
3974 * @height: (allow-none): location to store the default height, or %NULL
3975 *
3976 * Gets the default size of the window. A value of -1 for the width or
3977 * height indicates that a default size has not been explicitly set
3978 * for that dimension, so the "natural" size of the window will be
3979 * used.
3980 *
3981 **/
3982 void
gtk_window_get_default_size(GtkWindow * window,gint * width,gint * height)3983 gtk_window_get_default_size (GtkWindow *window,
3984 gint *width,
3985 gint *height)
3986 {
3987 GtkWindowGeometryInfo *info;
3988
3989 g_return_if_fail (GTK_IS_WINDOW (window));
3990
3991 info = gtk_window_get_geometry_info (window, FALSE);
3992
3993 if (width)
3994 *width = info ? info->default_width : -1;
3995
3996 if (height)
3997 *height = info ? info->default_height : -1;
3998 }
3999
4000 /**
4001 * gtk_window_resize:
4002 * @window: a #GtkWindow
4003 * @width: width in pixels to resize the window to
4004 * @height: height in pixels to resize the window to
4005 *
4006 * Resizes the window as if the user had done so, obeying geometry
4007 * constraints. The default geometry constraint is that windows may
4008 * not be smaller than their size request; to override this
4009 * constraint, call gtk_widget_set_size_request() to set the window's
4010 * request to a smaller value.
4011 *
4012 * If gtk_window_resize() is called before showing a window for the
4013 * first time, it overrides any default size set with
4014 * gtk_window_set_default_size().
4015 *
4016 * Windows may not be resized smaller than 1 by 1 pixels.
4017 *
4018 **/
4019 void
gtk_window_resize(GtkWindow * window,gint width,gint height)4020 gtk_window_resize (GtkWindow *window,
4021 gint width,
4022 gint height)
4023 {
4024 GtkWindowGeometryInfo *info;
4025
4026 g_return_if_fail (GTK_IS_WINDOW (window));
4027 g_return_if_fail (width > 0);
4028 g_return_if_fail (height > 0);
4029
4030 info = gtk_window_get_geometry_info (window, TRUE);
4031
4032 info->resize_width = width;
4033 info->resize_height = height;
4034
4035 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
4036 }
4037
4038 /**
4039 * gtk_window_get_size:
4040 * @window: a #GtkWindow
4041 * @width: (out) (allow-none): return location for width, or %NULL
4042 * @height: (out) (allow-none): return location for height, or %NULL
4043 *
4044 * Obtains the current size of @window. If @window is not onscreen,
4045 * it returns the size GTK+ will suggest to the <link
4046 * linkend="gtk-X11-arch">window manager</link> for the initial window
4047 * size (but this is not reliably the same as the size the window
4048 * manager will actually select). The size obtained by
4049 * gtk_window_get_size() is the last size received in a
4050 * #GdkEventConfigure, that is, GTK+ uses its locally-stored size,
4051 * rather than querying the X server for the size. As a result, if you
4052 * call gtk_window_resize() then immediately call
4053 * gtk_window_get_size(), the size won't have taken effect yet. After
4054 * the window manager processes the resize request, GTK+ receives
4055 * notification that the size has changed via a configure event, and
4056 * the size of the window gets updated.
4057 *
4058 * Note 1: Nearly any use of this function creates a race condition,
4059 * because the size of the window may change between the time that you
4060 * get the size and the time that you perform some action assuming
4061 * that size is the current size. To avoid race conditions, connect to
4062 * "configure-event" on the window and adjust your size-dependent
4063 * state to match the size delivered in the #GdkEventConfigure.
4064 *
4065 * Note 2: The returned size does <emphasis>not</emphasis> include the
4066 * size of the window manager decorations (aka the window frame or
4067 * border). Those are not drawn by GTK+ and GTK+ has no reliable
4068 * method of determining their size.
4069 *
4070 * Note 3: If you are getting a window size in order to position
4071 * the window onscreen, there may be a better way. The preferred
4072 * way is to simply set the window's semantic type with
4073 * gtk_window_set_type_hint(), which allows the window manager to
4074 * e.g. center dialogs. Also, if you set the transient parent of
4075 * dialogs with gtk_window_set_transient_for() window managers
4076 * will often center the dialog over its parent window. It's
4077 * much preferred to let the window manager handle these
4078 * things rather than doing it yourself, because all apps will
4079 * behave consistently and according to user prefs if the window
4080 * manager handles it. Also, the window manager can take the size
4081 * of the window decorations/border into account, while your
4082 * application cannot.
4083 *
4084 * In any case, if you insist on application-specified window
4085 * positioning, there's <emphasis>still</emphasis> a better way than
4086 * doing it yourself - gtk_window_set_position() will frequently
4087 * handle the details for you.
4088 *
4089 **/
4090 void
gtk_window_get_size(GtkWindow * window,gint * width,gint * height)4091 gtk_window_get_size (GtkWindow *window,
4092 gint *width,
4093 gint *height)
4094 {
4095 gint w, h;
4096
4097 g_return_if_fail (GTK_IS_WINDOW (window));
4098
4099 if (width == NULL && height == NULL)
4100 return;
4101
4102 if (gtk_widget_get_mapped (GTK_WIDGET (window)))
4103 {
4104 w = gdk_window_get_width (GTK_WIDGET (window)->window);
4105 h = gdk_window_get_height (GTK_WIDGET (window)->window);
4106 }
4107 else
4108 {
4109 GdkRectangle configure_request;
4110
4111 gtk_window_compute_configure_request (window,
4112 &configure_request,
4113 NULL, NULL);
4114
4115 w = configure_request.width;
4116 h = configure_request.height;
4117 }
4118
4119 if (width)
4120 *width = w;
4121 if (height)
4122 *height = h;
4123 }
4124
4125 /**
4126 * gtk_window_move:
4127 * @window: a #GtkWindow
4128 * @x: X coordinate to move window to
4129 * @y: Y coordinate to move window to
4130 *
4131 * Asks the <link linkend="gtk-X11-arch">window manager</link> to move
4132 * @window to the given position. Window managers are free to ignore
4133 * this; most window managers ignore requests for initial window
4134 * positions (instead using a user-defined placement algorithm) and
4135 * honor requests after the window has already been shown.
4136 *
4137 * Note: the position is the position of the gravity-determined
4138 * reference point for the window. The gravity determines two things:
4139 * first, the location of the reference point in root window
4140 * coordinates; and second, which point on the window is positioned at
4141 * the reference point.
4142 *
4143 * By default the gravity is #GDK_GRAVITY_NORTH_WEST, so the reference
4144 * point is simply the @x, @y supplied to gtk_window_move(). The
4145 * top-left corner of the window decorations (aka window frame or
4146 * border) will be placed at @x, @y. Therefore, to position a window
4147 * at the top left of the screen, you want to use the default gravity
4148 * (which is #GDK_GRAVITY_NORTH_WEST) and move the window to 0,0.
4149 *
4150 * To position a window at the bottom right corner of the screen, you
4151 * would set #GDK_GRAVITY_SOUTH_EAST, which means that the reference
4152 * point is at @x + the window width and @y + the window height, and
4153 * the bottom-right corner of the window border will be placed at that
4154 * reference point. So, to place a window in the bottom right corner
4155 * you would first set gravity to south east, then write:
4156 * <literal>gtk_window_move (window, gdk_screen_width () - window_width,
4157 * gdk_screen_height () - window_height)</literal> (note that this
4158 * example does not take multi-head scenarios into account).
4159 *
4160 * The Extended Window Manager Hints specification at <ulink
4161 * url="http://www.freedesktop.org/Standards/wm-spec">
4162 * http://www.freedesktop.org/Standards/wm-spec</ulink> has a
4163 * nice table of gravities in the "implementation notes" section.
4164 *
4165 * The gtk_window_get_position() documentation may also be relevant.
4166 */
4167 void
gtk_window_move(GtkWindow * window,gint x,gint y)4168 gtk_window_move (GtkWindow *window,
4169 gint x,
4170 gint y)
4171 {
4172 GtkWindowGeometryInfo *info;
4173 GtkWidget *widget;
4174
4175 g_return_if_fail (GTK_IS_WINDOW (window));
4176
4177 widget = GTK_WIDGET (window);
4178
4179 info = gtk_window_get_geometry_info (window, TRUE);
4180
4181 if (gtk_widget_get_mapped (widget))
4182 {
4183 /* we have now sent a request with this position
4184 * with currently-active constraints, so toggle flag.
4185 */
4186 info->position_constraints_changed = FALSE;
4187
4188 /* we only constrain if mapped - if not mapped,
4189 * then gtk_window_compute_configure_request()
4190 * will apply the constraints later, and we
4191 * don't want to lose information about
4192 * what position the user set before then.
4193 * i.e. if you do a move() then turn off POS_CENTER
4194 * then show the window, your move() will work.
4195 */
4196 gtk_window_constrain_position (window,
4197 widget->allocation.width,
4198 widget->allocation.height,
4199 &x, &y);
4200
4201 /* Note that this request doesn't go through our standard request
4202 * framework, e.g. doesn't increment configure_request_count,
4203 * doesn't set info->last, etc.; that's because
4204 * we don't save the info needed to arrive at this same request
4205 * again.
4206 *
4207 * To gtk_window_move_resize(), this will end up looking exactly
4208 * the same as the position being changed by the window
4209 * manager.
4210 */
4211
4212 /* FIXME are we handling gravity properly for framed windows? */
4213 if (window->frame)
4214 gdk_window_move (window->frame,
4215 x - window->frame_left,
4216 y - window->frame_top);
4217 else
4218 gdk_window_move (GTK_WIDGET (window)->window,
4219 x, y);
4220 }
4221 else
4222 {
4223 /* Save this position to apply on mapping */
4224 info->initial_x = x;
4225 info->initial_y = y;
4226 info->initial_pos_set = TRUE;
4227 }
4228 }
4229
4230 /**
4231 * gtk_window_get_position:
4232 * @window: a #GtkWindow
4233 * @root_x: (out) (allow-none): return location for X coordinate of gravity-determined reference point
4234 * @root_y: (out) (allow-none): return location for Y coordinate of gravity-determined reference point
4235 *
4236 * This function returns the position you need to pass to
4237 * gtk_window_move() to keep @window in its current position. This
4238 * means that the meaning of the returned value varies with window
4239 * gravity. See gtk_window_move() for more details.
4240 *
4241 * If you haven't changed the window gravity, its gravity will be
4242 * #GDK_GRAVITY_NORTH_WEST. This means that gtk_window_get_position()
4243 * gets the position of the top-left corner of the window manager
4244 * frame for the window. gtk_window_move() sets the position of this
4245 * same top-left corner.
4246 *
4247 * gtk_window_get_position() is not 100% reliable because the X Window System
4248 * does not specify a way to obtain the geometry of the
4249 * decorations placed on a window by the window manager.
4250 * Thus GTK+ is using a "best guess" that works with most
4251 * window managers.
4252 *
4253 * Moreover, nearly all window managers are historically broken with
4254 * respect to their handling of window gravity. So moving a window to
4255 * its current position as returned by gtk_window_get_position() tends
4256 * to result in moving the window slightly. Window managers are
4257 * slowly getting better over time.
4258 *
4259 * If a window has gravity #GDK_GRAVITY_STATIC the window manager
4260 * frame is not relevant, and thus gtk_window_get_position() will
4261 * always produce accurate results. However you can't use static
4262 * gravity to do things like place a window in a corner of the screen,
4263 * because static gravity ignores the window manager decorations.
4264 *
4265 * If you are saving and restoring your application's window
4266 * positions, you should know that it's impossible for applications to
4267 * do this without getting it somewhat wrong because applications do
4268 * not have sufficient knowledge of window manager state. The Correct
4269 * Mechanism is to support the session management protocol (see the
4270 * "GnomeClient" object in the GNOME libraries for example) and allow
4271 * the window manager to save your window sizes and positions.
4272 *
4273 **/
4274
4275 void
gtk_window_get_position(GtkWindow * window,gint * root_x,gint * root_y)4276 gtk_window_get_position (GtkWindow *window,
4277 gint *root_x,
4278 gint *root_y)
4279 {
4280 GtkWidget *widget;
4281
4282 g_return_if_fail (GTK_IS_WINDOW (window));
4283
4284 widget = GTK_WIDGET (window);
4285
4286 if (window->gravity == GDK_GRAVITY_STATIC)
4287 {
4288 if (gtk_widget_get_mapped (widget))
4289 {
4290 /* This does a server round-trip, which is sort of wrong;
4291 * but a server round-trip is inevitable for
4292 * gdk_window_get_frame_extents() in the usual
4293 * NorthWestGravity case below, so not sure what else to
4294 * do. We should likely be consistent about whether we get
4295 * the client-side info or the server-side info.
4296 */
4297 gdk_window_get_origin (widget->window, root_x, root_y);
4298 }
4299 else
4300 {
4301 GdkRectangle configure_request;
4302
4303 gtk_window_compute_configure_request (window,
4304 &configure_request,
4305 NULL, NULL);
4306
4307 *root_x = configure_request.x;
4308 *root_y = configure_request.y;
4309 }
4310 }
4311 else
4312 {
4313 GdkRectangle frame_extents;
4314
4315 gint x, y;
4316 gint w, h;
4317
4318 if (gtk_widget_get_mapped (widget))
4319 {
4320 if (window->frame)
4321 gdk_window_get_frame_extents (window->frame, &frame_extents);
4322 else
4323 gdk_window_get_frame_extents (widget->window, &frame_extents);
4324 x = frame_extents.x;
4325 y = frame_extents.y;
4326 gtk_window_get_size (window, &w, &h);
4327 }
4328 else
4329 {
4330 /* We just say the frame has 0 size on all sides.
4331 * Not sure what else to do.
4332 */
4333 gtk_window_compute_configure_request (window,
4334 &frame_extents,
4335 NULL, NULL);
4336 x = frame_extents.x;
4337 y = frame_extents.y;
4338 w = frame_extents.width;
4339 h = frame_extents.height;
4340 }
4341
4342 switch (window->gravity)
4343 {
4344 case GDK_GRAVITY_NORTH:
4345 case GDK_GRAVITY_CENTER:
4346 case GDK_GRAVITY_SOUTH:
4347 /* Find center of frame. */
4348 x += frame_extents.width / 2;
4349 /* Center client window on that point. */
4350 x -= w / 2;
4351 break;
4352
4353 case GDK_GRAVITY_SOUTH_EAST:
4354 case GDK_GRAVITY_EAST:
4355 case GDK_GRAVITY_NORTH_EAST:
4356 /* Find right edge of frame */
4357 x += frame_extents.width;
4358 /* Align left edge of client at that point. */
4359 x -= w;
4360 break;
4361 default:
4362 break;
4363 }
4364
4365 switch (window->gravity)
4366 {
4367 case GDK_GRAVITY_WEST:
4368 case GDK_GRAVITY_CENTER:
4369 case GDK_GRAVITY_EAST:
4370 /* Find center of frame. */
4371 y += frame_extents.height / 2;
4372 /* Center client window there. */
4373 y -= h / 2;
4374 break;
4375 case GDK_GRAVITY_SOUTH_WEST:
4376 case GDK_GRAVITY_SOUTH:
4377 case GDK_GRAVITY_SOUTH_EAST:
4378 /* Find south edge of frame */
4379 y += frame_extents.height;
4380 /* Place bottom edge of client there */
4381 y -= h;
4382 break;
4383 default:
4384 break;
4385 }
4386
4387 if (root_x)
4388 *root_x = x;
4389 if (root_y)
4390 *root_y = y;
4391 }
4392 }
4393
4394 /**
4395 * gtk_window_reshow_with_initial_size:
4396 * @window: a #GtkWindow
4397 *
4398 * Hides @window, then reshows it, resetting the
4399 * default size and position of the window. Used
4400 * by GUI builders only.
4401 **/
4402 void
gtk_window_reshow_with_initial_size(GtkWindow * window)4403 gtk_window_reshow_with_initial_size (GtkWindow *window)
4404 {
4405 GtkWidget *widget;
4406
4407 g_return_if_fail (GTK_IS_WINDOW (window));
4408
4409 widget = GTK_WIDGET (window);
4410
4411 gtk_widget_hide (widget);
4412 gtk_widget_unrealize (widget);
4413 gtk_widget_show (widget);
4414 }
4415
4416 static void
gtk_window_destroy(GtkObject * object)4417 gtk_window_destroy (GtkObject *object)
4418 {
4419 GtkWindow *window = GTK_WINDOW (object);
4420
4421 toplevel_list = g_slist_remove (toplevel_list, window);
4422
4423 if (window->transient_parent)
4424 gtk_window_set_transient_for (window, NULL);
4425
4426 /* frees the icons */
4427 gtk_window_set_icon_list (window, NULL);
4428
4429 if (window->has_user_ref_count)
4430 {
4431 window->has_user_ref_count = FALSE;
4432 g_object_unref (window);
4433 }
4434
4435 if (window->group)
4436 gtk_window_group_remove_window (window->group, window);
4437
4438 gtk_window_free_key_hash (window);
4439
4440 GTK_OBJECT_CLASS (gtk_window_parent_class)->destroy (object);
4441 }
4442
4443 static void
gtk_window_finalize(GObject * object)4444 gtk_window_finalize (GObject *object)
4445 {
4446 GtkWindow *window = GTK_WINDOW (object);
4447 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
4448 GtkMnemonicHash *mnemonic_hash;
4449
4450 g_free (window->title);
4451 g_free (window->wmclass_name);
4452 g_free (window->wmclass_class);
4453 g_free (window->wm_role);
4454
4455 mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
4456 if (mnemonic_hash)
4457 _gtk_mnemonic_hash_free (mnemonic_hash);
4458
4459 if (window->geometry_info)
4460 {
4461 if (window->geometry_info->widget)
4462 g_signal_handlers_disconnect_by_func (window->geometry_info->widget,
4463 gtk_widget_destroyed,
4464 &window->geometry_info->widget);
4465 g_free (window->geometry_info);
4466 }
4467
4468 if (window->keys_changed_handler)
4469 {
4470 g_source_remove (window->keys_changed_handler);
4471 window->keys_changed_handler = 0;
4472 }
4473
4474 if (window->screen)
4475 g_signal_handlers_disconnect_by_func (window->screen,
4476 gtk_window_on_composited_changed, window);
4477
4478 g_free (priv->startup_id);
4479
4480 G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
4481 }
4482
4483 static void
gtk_window_show(GtkWidget * widget)4484 gtk_window_show (GtkWidget *widget)
4485 {
4486 GtkWindow *window = GTK_WINDOW (widget);
4487 GtkContainer *container = GTK_CONTAINER (window);
4488 gboolean need_resize;
4489
4490 GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
4491
4492 need_resize = container->need_resize || !gtk_widget_get_realized (widget);
4493 container->need_resize = FALSE;
4494
4495 if (need_resize)
4496 {
4497 GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
4498 GtkAllocation allocation = { 0, 0 };
4499 GdkRectangle configure_request;
4500 GdkGeometry new_geometry;
4501 guint new_flags;
4502 gboolean was_realized;
4503
4504 /* We are going to go ahead and perform this configure request
4505 * and then emulate a configure notify by going ahead and
4506 * doing a size allocate. Sort of a synchronous
4507 * mini-copy of gtk_window_move_resize() here.
4508 */
4509 gtk_window_compute_configure_request (window,
4510 &configure_request,
4511 &new_geometry,
4512 &new_flags);
4513
4514 /* We update this because we are going to go ahead
4515 * and gdk_window_resize() below, rather than
4516 * queuing it.
4517 */
4518 info->last.configure_request.width = configure_request.width;
4519 info->last.configure_request.height = configure_request.height;
4520
4521 /* and allocate the window - this is normally done
4522 * in move_resize in response to configure notify
4523 */
4524 allocation.width = configure_request.width;
4525 allocation.height = configure_request.height;
4526 gtk_widget_size_allocate (widget, &allocation);
4527
4528 /* Then we guarantee we have a realize */
4529 was_realized = FALSE;
4530 if (!gtk_widget_get_realized (widget))
4531 {
4532 gtk_widget_realize (widget);
4533 was_realized = TRUE;
4534 }
4535
4536 /* Must be done after the windows are realized,
4537 * so that the decorations can be read
4538 */
4539 gtk_decorated_window_calculate_frame_size (window);
4540
4541 /* We only send configure request if we didn't just finish
4542 * creating the window; if we just created the window
4543 * then we created it with widget->allocation anyhow.
4544 */
4545 if (!was_realized)
4546 gdk_window_move_resize (widget->window,
4547 configure_request.x,
4548 configure_request.y,
4549 configure_request.width,
4550 configure_request.height);
4551 }
4552
4553 gtk_container_check_resize (container);
4554
4555 gtk_widget_map (widget);
4556
4557 /* Try to make sure that we have some focused widget
4558 */
4559 if (!window->focus_widget && !GTK_IS_PLUG (window))
4560 gtk_window_move_focus (window, GTK_DIR_TAB_FORWARD);
4561
4562 if (window->modal)
4563 gtk_grab_add (widget);
4564 }
4565
4566 static void
gtk_window_hide(GtkWidget * widget)4567 gtk_window_hide (GtkWidget *widget)
4568 {
4569 GtkWindow *window = GTK_WINDOW (widget);
4570
4571 GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
4572 gtk_widget_unmap (widget);
4573
4574 if (window->modal)
4575 gtk_grab_remove (widget);
4576 }
4577
4578 static void
gtk_window_map(GtkWidget * widget)4579 gtk_window_map (GtkWidget *widget)
4580 {
4581 GtkWindow *window = GTK_WINDOW (widget);
4582 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
4583 GdkWindow *toplevel;
4584 gboolean auto_mnemonics;
4585
4586 gtk_widget_set_mapped (widget, TRUE);
4587
4588 if (window->bin.child &&
4589 gtk_widget_get_visible (window->bin.child) &&
4590 !gtk_widget_get_mapped (window->bin.child))
4591 gtk_widget_map (window->bin.child);
4592
4593 if (window->frame)
4594 toplevel = window->frame;
4595 else
4596 toplevel = widget->window;
4597
4598 if (window->maximize_initially)
4599 gdk_window_maximize (toplevel);
4600 else
4601 gdk_window_unmaximize (toplevel);
4602
4603 if (window->stick_initially)
4604 gdk_window_stick (toplevel);
4605 else
4606 gdk_window_unstick (toplevel);
4607
4608 if (window->iconify_initially)
4609 gdk_window_iconify (toplevel);
4610 else
4611 gdk_window_deiconify (toplevel);
4612
4613 if (priv->fullscreen_initially)
4614 gdk_window_fullscreen (toplevel);
4615 else
4616 gdk_window_unfullscreen (toplevel);
4617
4618 gdk_window_set_keep_above (toplevel, priv->above_initially);
4619
4620 gdk_window_set_keep_below (toplevel, priv->below_initially);
4621
4622 /* No longer use the default settings */
4623 window->need_default_size = FALSE;
4624 window->need_default_position = FALSE;
4625
4626 if (priv->reset_type_hint)
4627 {
4628 /* We should only reset the type hint when the application
4629 * used gtk_window_set_type_hint() to change the hint.
4630 * Some applications use X directly to change the properties;
4631 * in that case, we shouldn't overwrite what they did.
4632 */
4633 gdk_window_set_type_hint (widget->window, priv->type_hint);
4634 priv->reset_type_hint = FALSE;
4635 }
4636
4637 gdk_window_show (widget->window);
4638
4639 if (window->frame)
4640 gdk_window_show (window->frame);
4641
4642 if (!disable_startup_notification)
4643 {
4644 /* Do we have a custom startup-notification id? */
4645 if (priv->startup_id != NULL)
4646 {
4647 /* Make sure we have a "real" id */
4648 if (!startup_id_is_fake (priv->startup_id))
4649 gdk_notify_startup_complete_with_id (priv->startup_id);
4650
4651 g_free (priv->startup_id);
4652 priv->startup_id = NULL;
4653 }
4654 else if (!sent_startup_notification)
4655 {
4656 sent_startup_notification = TRUE;
4657 gdk_notify_startup_complete ();
4658 }
4659 }
4660
4661 /* if auto-mnemonics is enabled and mnemonics visible is not already set
4662 * (as in the case of popup menus), then hide mnemonics initially
4663 */
4664 g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
4665 &auto_mnemonics, NULL);
4666 if (auto_mnemonics && !priv->mnemonics_visible_set)
4667 gtk_window_set_mnemonics_visible (window, FALSE);
4668 }
4669
4670 static gboolean
gtk_window_map_event(GtkWidget * widget,GdkEventAny * event)4671 gtk_window_map_event (GtkWidget *widget,
4672 GdkEventAny *event)
4673 {
4674 if (!gtk_widget_get_mapped (widget))
4675 {
4676 /* we should be be unmapped, but are getting a MapEvent, this may happen
4677 * to toplevel XWindows if mapping was intercepted by a window manager
4678 * and an unmap request occoured while the MapRequestEvent was still
4679 * being handled. we work around this situaiton here by re-requesting
4680 * the window being unmapped. more details can be found in:
4681 * http://bugzilla.gnome.org/show_bug.cgi?id=316180
4682 */
4683 gdk_window_hide (widget->window);
4684 }
4685 return FALSE;
4686 }
4687
4688 static void
gtk_window_unmap(GtkWidget * widget)4689 gtk_window_unmap (GtkWidget *widget)
4690 {
4691 GtkWindow *window = GTK_WINDOW (widget);
4692 GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (widget);
4693 GtkWindowGeometryInfo *info;
4694 GdkWindowState state;
4695
4696 gtk_widget_set_mapped (widget, FALSE);
4697 if (window->frame)
4698 gdk_window_withdraw (window->frame);
4699 else
4700 gdk_window_withdraw (widget->window);
4701
4702 window->configure_request_count = 0;
4703 window->configure_notify_received = FALSE;
4704
4705 /* on unmap, we reset the default positioning of the window,
4706 * so it's placed again, but we don't reset the default
4707 * size of the window, so it's remembered.
4708 */
4709 window->need_default_position = TRUE;
4710
4711 info = gtk_window_get_geometry_info (window, FALSE);
4712 if (info)
4713 {
4714 info->initial_pos_set = FALSE;
4715 info->position_constraints_changed = FALSE;
4716 }
4717
4718 state = gdk_window_get_state (widget->window);
4719 window->iconify_initially = (state & GDK_WINDOW_STATE_ICONIFIED) != 0;
4720 window->maximize_initially = (state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
4721 window->stick_initially = (state & GDK_WINDOW_STATE_STICKY) != 0;
4722 priv->above_initially = (state & GDK_WINDOW_STATE_ABOVE) != 0;
4723 priv->below_initially = (state & GDK_WINDOW_STATE_BELOW) != 0;
4724 }
4725
4726 static void
gtk_window_realize(GtkWidget * widget)4727 gtk_window_realize (GtkWidget *widget)
4728 {
4729 GtkWindow *window;
4730 GdkWindow *parent_window;
4731 GdkWindowAttr attributes;
4732 gint attributes_mask;
4733 GtkWindowPrivate *priv;
4734
4735 window = GTK_WINDOW (widget);
4736 priv = GTK_WINDOW_GET_PRIVATE (window);
4737
4738 /* ensure widget tree is properly size allocated */
4739 if (widget->allocation.x == -1 &&
4740 widget->allocation.y == -1 &&
4741 widget->allocation.width == 1 &&
4742 widget->allocation.height == 1)
4743 {
4744 GtkRequisition requisition;
4745 GtkAllocation allocation = { 0, 0, 200, 200 };
4746
4747 gtk_widget_size_request (widget, &requisition);
4748 if (requisition.width || requisition.height)
4749 {
4750 /* non-empty window */
4751 allocation.width = requisition.width;
4752 allocation.height = requisition.height;
4753 }
4754 gtk_widget_size_allocate (widget, &allocation);
4755
4756 _gtk_container_queue_resize (GTK_CONTAINER (widget));
4757
4758 g_return_if_fail (!gtk_widget_get_realized (widget));
4759 }
4760
4761 gtk_widget_set_realized (widget, TRUE);
4762
4763 switch (window->type)
4764 {
4765 case GTK_WINDOW_TOPLEVEL:
4766 attributes.window_type = GDK_WINDOW_TOPLEVEL;
4767 break;
4768 case GTK_WINDOW_POPUP:
4769 attributes.window_type = GDK_WINDOW_TEMP;
4770 break;
4771 default:
4772 g_warning (G_STRLOC": Unknown window type %d!", window->type);
4773 break;
4774 }
4775
4776 attributes.title = window->title;
4777 attributes.wmclass_name = window->wmclass_name;
4778 attributes.wmclass_class = window->wmclass_class;
4779 attributes.wclass = GDK_INPUT_OUTPUT;
4780 attributes.visual = gtk_widget_get_visual (widget);
4781 attributes.colormap = gtk_widget_get_colormap (widget);
4782
4783 if (window->has_frame)
4784 {
4785 attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
4786 attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
4787 attributes.event_mask = (GDK_EXPOSURE_MASK |
4788 GDK_KEY_PRESS_MASK |
4789 GDK_ENTER_NOTIFY_MASK |
4790 GDK_LEAVE_NOTIFY_MASK |
4791 GDK_FOCUS_CHANGE_MASK |
4792 GDK_STRUCTURE_MASK |
4793 GDK_BUTTON_MOTION_MASK |
4794 GDK_POINTER_MOTION_HINT_MASK |
4795 GDK_BUTTON_PRESS_MASK |
4796 GDK_BUTTON_RELEASE_MASK);
4797
4798 attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
4799
4800 window->frame = gdk_window_new (gtk_widget_get_root_window (widget),
4801 &attributes, attributes_mask);
4802
4803 if (priv->opacity_set)
4804 gdk_window_set_opacity (window->frame, priv->opacity);
4805
4806 gdk_window_set_user_data (window->frame, widget);
4807
4808 attributes.window_type = GDK_WINDOW_CHILD;
4809 attributes.x = window->frame_left;
4810 attributes.y = window->frame_top;
4811
4812 attributes_mask = GDK_WA_X | GDK_WA_Y;
4813
4814 parent_window = window->frame;
4815
4816 g_signal_connect (window,
4817 "event",
4818 G_CALLBACK (gtk_window_event),
4819 NULL);
4820 }
4821 else
4822 {
4823 attributes_mask = 0;
4824 parent_window = gtk_widget_get_root_window (widget);
4825 }
4826
4827 attributes.width = widget->allocation.width;
4828 attributes.height = widget->allocation.height;
4829 attributes.event_mask = gtk_widget_get_events (widget);
4830 attributes.event_mask |= (GDK_EXPOSURE_MASK |
4831 GDK_KEY_PRESS_MASK |
4832 GDK_KEY_RELEASE_MASK |
4833 GDK_ENTER_NOTIFY_MASK |
4834 GDK_LEAVE_NOTIFY_MASK |
4835 GDK_FOCUS_CHANGE_MASK |
4836 GDK_STRUCTURE_MASK);
4837 attributes.type_hint = priv->type_hint;
4838
4839 attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_TYPE_HINT;
4840 attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
4841 attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
4842
4843 widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
4844
4845 if (!window->has_frame && priv->opacity_set)
4846 gdk_window_set_opacity (widget->window, priv->opacity);
4847
4848 gdk_window_enable_synchronized_configure (widget->window);
4849
4850 gdk_window_set_user_data (widget->window, window);
4851
4852 widget->style = gtk_style_attach (widget->style, widget->window);
4853 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
4854 if (window->frame)
4855 gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
4856
4857 /* This is a bad hack to set the window background. */
4858 gtk_window_paint (widget, NULL);
4859
4860 if (window->transient_parent &&
4861 gtk_widget_get_realized (GTK_WIDGET (window->transient_parent)))
4862 gdk_window_set_transient_for (widget->window,
4863 GTK_WIDGET (window->transient_parent)->window);
4864
4865 if (window->wm_role)
4866 gdk_window_set_role (widget->window, window->wm_role);
4867
4868 if (!window->decorated)
4869 gdk_window_set_decorations (widget->window, 0);
4870
4871 if (!priv->deletable)
4872 gdk_window_set_functions (widget->window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
4873
4874 if (gtk_window_get_skip_pager_hint (window))
4875 gdk_window_set_skip_pager_hint (widget->window, TRUE);
4876
4877 if (gtk_window_get_skip_taskbar_hint (window))
4878 gdk_window_set_skip_taskbar_hint (widget->window, TRUE);
4879
4880 if (gtk_window_get_accept_focus (window))
4881 gdk_window_set_accept_focus (widget->window, TRUE);
4882 else
4883 gdk_window_set_accept_focus (widget->window, FALSE);
4884
4885 if (gtk_window_get_focus_on_map (window))
4886 gdk_window_set_focus_on_map (widget->window, TRUE);
4887 else
4888 gdk_window_set_focus_on_map (widget->window, FALSE);
4889
4890 if (window->modal)
4891 gdk_window_set_modal_hint (widget->window, TRUE);
4892 else
4893 gdk_window_set_modal_hint (widget->window, FALSE);
4894
4895 if (priv->startup_id)
4896 {
4897 #ifdef GDK_WINDOWING_X11
4898 guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
4899 if (timestamp != GDK_CURRENT_TIME)
4900 gdk_x11_window_set_user_time (widget->window, timestamp);
4901 #endif
4902 if (!startup_id_is_fake (priv->startup_id))
4903 gdk_window_set_startup_id (widget->window, priv->startup_id);
4904 }
4905
4906 /* Icons */
4907 gtk_window_realize_icon (window);
4908 }
4909
4910 static void
gtk_window_unrealize(GtkWidget * widget)4911 gtk_window_unrealize (GtkWidget *widget)
4912 {
4913 GtkWindow *window;
4914 GtkWindowGeometryInfo *info;
4915
4916 window = GTK_WINDOW (widget);
4917
4918 /* On unrealize, we reset the size of the window such
4919 * that we will re-apply the default sizing stuff
4920 * next time we show the window.
4921 *
4922 * Default positioning is reset on unmap, instead of unrealize.
4923 */
4924 window->need_default_size = TRUE;
4925 info = gtk_window_get_geometry_info (window, FALSE);
4926 if (info)
4927 {
4928 info->resize_width = -1;
4929 info->resize_height = -1;
4930 info->last.configure_request.x = 0;
4931 info->last.configure_request.y = 0;
4932 info->last.configure_request.width = -1;
4933 info->last.configure_request.height = -1;
4934 /* be sure we reset geom hints on re-realize */
4935 info->last.flags = 0;
4936 }
4937
4938 if (window->frame)
4939 {
4940 gdk_window_set_user_data (window->frame, NULL);
4941 gdk_window_destroy (window->frame);
4942 window->frame = NULL;
4943 }
4944
4945 /* Icons */
4946 gtk_window_unrealize_icon (window);
4947
4948 GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
4949 }
4950
4951 static void
gtk_window_size_request(GtkWidget * widget,GtkRequisition * requisition)4952 gtk_window_size_request (GtkWidget *widget,
4953 GtkRequisition *requisition)
4954 {
4955 GtkWindow *window;
4956 GtkBin *bin;
4957
4958 window = GTK_WINDOW (widget);
4959 bin = GTK_BIN (window);
4960
4961 requisition->width = GTK_CONTAINER (window)->border_width * 2;
4962 requisition->height = GTK_CONTAINER (window)->border_width * 2;
4963
4964 if (bin->child && gtk_widget_get_visible (bin->child))
4965 {
4966 GtkRequisition child_requisition;
4967
4968 gtk_widget_size_request (bin->child, &child_requisition);
4969
4970 requisition->width += child_requisition.width;
4971 requisition->height += child_requisition.height;
4972 }
4973 }
4974
4975 static void
gtk_window_size_allocate(GtkWidget * widget,GtkAllocation * allocation)4976 gtk_window_size_allocate (GtkWidget *widget,
4977 GtkAllocation *allocation)
4978 {
4979 GtkWindow *window;
4980 GtkAllocation child_allocation;
4981
4982 window = GTK_WINDOW (widget);
4983 widget->allocation = *allocation;
4984
4985 if (window->bin.child && gtk_widget_get_visible (window->bin.child))
4986 {
4987 child_allocation.x = GTK_CONTAINER (window)->border_width;
4988 child_allocation.y = GTK_CONTAINER (window)->border_width;
4989 child_allocation.width =
4990 MAX (1, (gint)allocation->width - child_allocation.x * 2);
4991 child_allocation.height =
4992 MAX (1, (gint)allocation->height - child_allocation.y * 2);
4993
4994 gtk_widget_size_allocate (window->bin.child, &child_allocation);
4995 }
4996
4997 if (gtk_widget_get_realized (widget) && window->frame)
4998 {
4999 gdk_window_resize (window->frame,
5000 allocation->width + window->frame_left + window->frame_right,
5001 allocation->height + window->frame_top + window->frame_bottom);
5002 }
5003 }
5004
5005 static gint
gtk_window_event(GtkWidget * widget,GdkEvent * event)5006 gtk_window_event (GtkWidget *widget, GdkEvent *event)
5007 {
5008 GtkWindow *window;
5009 gboolean return_val;
5010
5011 window = GTK_WINDOW (widget);
5012
5013 if (window->frame && (event->any.window == window->frame))
5014 {
5015 if ((event->type != GDK_KEY_PRESS) &&
5016 (event->type != GDK_KEY_RELEASE) &&
5017 (event->type != GDK_FOCUS_CHANGE))
5018 {
5019 g_signal_stop_emission_by_name (widget, "event");
5020 return_val = FALSE;
5021 g_signal_emit (widget, window_signals[FRAME_EVENT], 0, event, &return_val);
5022 return TRUE;
5023 }
5024 else
5025 {
5026 g_object_unref (event->any.window);
5027 event->any.window = g_object_ref (widget->window);
5028 }
5029 }
5030
5031 return FALSE;
5032 }
5033
5034 static gboolean
gtk_window_frame_event(GtkWindow * window,GdkEvent * event)5035 gtk_window_frame_event (GtkWindow *window, GdkEvent *event)
5036 {
5037 GdkEventConfigure *configure_event;
5038 GdkRectangle rect;
5039
5040 switch (event->type)
5041 {
5042 case GDK_CONFIGURE:
5043 configure_event = (GdkEventConfigure *)event;
5044
5045 /* Invalidate the decorations */
5046 rect.x = 0;
5047 rect.y = 0;
5048 rect.width = configure_event->width;
5049 rect.height = configure_event->height;
5050
5051 gdk_window_invalidate_rect (window->frame, &rect, FALSE);
5052
5053 /* Pass on the (modified) configure event */
5054 configure_event->width -= window->frame_left + window->frame_right;
5055 configure_event->height -= window->frame_top + window->frame_bottom;
5056 return gtk_window_configure_event (GTK_WIDGET (window), configure_event);
5057 break;
5058 default:
5059 break;
5060 }
5061 return FALSE;
5062 }
5063
5064 static gint
gtk_window_configure_event(GtkWidget * widget,GdkEventConfigure * event)5065 gtk_window_configure_event (GtkWidget *widget,
5066 GdkEventConfigure *event)
5067 {
5068 GtkWindow *window = GTK_WINDOW (widget);
5069 gboolean expected_reply = window->configure_request_count > 0;
5070
5071 /* window->configure_request_count incremented for each
5072 * configure request, and decremented to a min of 0 for
5073 * each configure notify.
5074 *
5075 * All it means is that we know we will get at least
5076 * window->configure_request_count more configure notifies.
5077 * We could get more configure notifies than that; some
5078 * of the configure notifies we get may be unrelated to
5079 * the configure requests. But we will get at least
5080 * window->configure_request_count notifies.
5081 */
5082
5083 if (window->configure_request_count > 0)
5084 {
5085 window->configure_request_count -= 1;
5086 gdk_window_thaw_toplevel_updates_libgtk_only (widget->window);
5087 }
5088
5089 /* As an optimization, we avoid a resize when possible.
5090 *
5091 * The only times we can avoid a resize are:
5092 * - we know only the position changed, not the size
5093 * - we know we have made more requests and so will get more
5094 * notifies and can wait to resize when we get them
5095 */
5096
5097 if (!expected_reply &&
5098 (widget->allocation.width == event->width &&
5099 widget->allocation.height == event->height))
5100 {
5101 gdk_window_configure_finished (widget->window);
5102 return TRUE;
5103 }
5104
5105 /*
5106 * If we do need to resize, we do that by:
5107 * - filling in widget->allocation with the new size
5108 * - setting configure_notify_received to TRUE
5109 * for use in gtk_window_move_resize()
5110 * - queueing a resize, leading to invocation of
5111 * gtk_window_move_resize() in an idle handler
5112 *
5113 */
5114
5115 window->configure_notify_received = TRUE;
5116
5117 widget->allocation.width = event->width;
5118 widget->allocation.height = event->height;
5119
5120 _gtk_container_queue_resize (GTK_CONTAINER (widget));
5121
5122 return TRUE;
5123 }
5124
5125 /* the accel_key and accel_mods fields of the key have to be setup
5126 * upon calling this function. it'll then return whether that key
5127 * is at all used as accelerator, and if so will OR in the
5128 * accel_flags member of the key.
5129 */
5130 gboolean
_gtk_window_query_nonaccels(GtkWindow * window,guint accel_key,GdkModifierType accel_mods)5131 _gtk_window_query_nonaccels (GtkWindow *window,
5132 guint accel_key,
5133 GdkModifierType accel_mods)
5134 {
5135 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5136
5137 /* movement keys are considered locked accels */
5138 if (!accel_mods)
5139 {
5140 static const guint bindings[] = {
5141 GDK_space, GDK_KP_Space, GDK_Return, GDK_ISO_Enter, GDK_KP_Enter, GDK_Up, GDK_KP_Up, GDK_Down, GDK_KP_Down,
5142 GDK_Left, GDK_KP_Left, GDK_Right, GDK_KP_Right, GDK_Tab, GDK_KP_Tab, GDK_ISO_Left_Tab,
5143 };
5144 guint i;
5145
5146 for (i = 0; i < G_N_ELEMENTS (bindings); i++)
5147 if (bindings[i] == accel_key)
5148 return TRUE;
5149 }
5150
5151 /* mnemonics are considered locked accels */
5152 if (accel_mods == window->mnemonic_modifier)
5153 {
5154 GtkMnemonicHash *mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
5155 if (mnemonic_hash && _gtk_mnemonic_hash_lookup (mnemonic_hash, accel_key))
5156 return TRUE;
5157 }
5158
5159 return FALSE;
5160 }
5161
5162 /**
5163 * gtk_window_propagate_key_event:
5164 * @window: a #GtkWindow
5165 * @event: a #GdkEventKey
5166 *
5167 * Propagate a key press or release event to the focus widget and
5168 * up the focus container chain until a widget handles @event.
5169 * This is normally called by the default ::key_press_event and
5170 * ::key_release_event handlers for toplevel windows,
5171 * however in some cases it may be useful to call this directly when
5172 * overriding the standard key handling for a toplevel window.
5173 *
5174 * Return value: %TRUE if a widget in the focus chain handled the event.
5175 *
5176 * Since: 2.4
5177 */
5178 gboolean
gtk_window_propagate_key_event(GtkWindow * window,GdkEventKey * event)5179 gtk_window_propagate_key_event (GtkWindow *window,
5180 GdkEventKey *event)
5181 {
5182 gboolean handled = FALSE;
5183 GtkWidget *widget, *focus;
5184
5185 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5186
5187 widget = GTK_WIDGET (window);
5188 focus = window->focus_widget;
5189 if (focus)
5190 g_object_ref (focus);
5191
5192 while (!handled &&
5193 focus && focus != widget &&
5194 gtk_widget_get_toplevel (focus) == widget)
5195 {
5196 GtkWidget *parent;
5197
5198 if (gtk_widget_is_sensitive (focus))
5199 handled = gtk_widget_event (focus, (GdkEvent*) event);
5200
5201 parent = focus->parent;
5202 if (parent)
5203 g_object_ref (parent);
5204
5205 g_object_unref (focus);
5206
5207 focus = parent;
5208 }
5209
5210 if (focus)
5211 g_object_unref (focus);
5212
5213 return handled;
5214 }
5215
5216 static gint
gtk_window_key_press_event(GtkWidget * widget,GdkEventKey * event)5217 gtk_window_key_press_event (GtkWidget *widget,
5218 GdkEventKey *event)
5219 {
5220 GtkWindow *window = GTK_WINDOW (widget);
5221 gboolean handled = FALSE;
5222
5223 /* handle mnemonics and accelerators */
5224 if (!handled)
5225 handled = gtk_window_activate_key (window, event);
5226
5227 /* handle focus widget key events */
5228 if (!handled)
5229 handled = gtk_window_propagate_key_event (window, event);
5230
5231 /* Chain up, invokes binding set */
5232 if (!handled)
5233 handled = GTK_WIDGET_CLASS (gtk_window_parent_class)->key_press_event (widget, event);
5234
5235 return handled;
5236 }
5237
5238 static gint
gtk_window_key_release_event(GtkWidget * widget,GdkEventKey * event)5239 gtk_window_key_release_event (GtkWidget *widget,
5240 GdkEventKey *event)
5241 {
5242 GtkWindow *window = GTK_WINDOW (widget);
5243 gboolean handled = FALSE;
5244
5245 /* handle focus widget key events */
5246 if (!handled)
5247 handled = gtk_window_propagate_key_event (window, event);
5248
5249 /* Chain up, invokes binding set */
5250 if (!handled)
5251 handled = GTK_WIDGET_CLASS (gtk_window_parent_class)->key_release_event (widget, event);
5252
5253 return handled;
5254 }
5255
5256 static void
gtk_window_real_activate_default(GtkWindow * window)5257 gtk_window_real_activate_default (GtkWindow *window)
5258 {
5259 gtk_window_activate_default (window);
5260 }
5261
5262 static void
gtk_window_real_activate_focus(GtkWindow * window)5263 gtk_window_real_activate_focus (GtkWindow *window)
5264 {
5265 gtk_window_activate_focus (window);
5266 }
5267
5268 static void
gtk_window_move_focus(GtkWindow * window,GtkDirectionType dir)5269 gtk_window_move_focus (GtkWindow *window,
5270 GtkDirectionType dir)
5271 {
5272 gtk_widget_child_focus (GTK_WIDGET (window), dir);
5273
5274 if (!GTK_CONTAINER (window)->focus_child)
5275 gtk_window_set_focus (window, NULL);
5276 }
5277
5278 static gint
gtk_window_enter_notify_event(GtkWidget * widget,GdkEventCrossing * event)5279 gtk_window_enter_notify_event (GtkWidget *widget,
5280 GdkEventCrossing *event)
5281 {
5282 return FALSE;
5283 }
5284
5285 static gint
gtk_window_leave_notify_event(GtkWidget * widget,GdkEventCrossing * event)5286 gtk_window_leave_notify_event (GtkWidget *widget,
5287 GdkEventCrossing *event)
5288 {
5289 return FALSE;
5290 }
5291
5292 static void
do_focus_change(GtkWidget * widget,gboolean in)5293 do_focus_change (GtkWidget *widget,
5294 gboolean in)
5295 {
5296 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
5297
5298 fevent->focus_change.type = GDK_FOCUS_CHANGE;
5299 fevent->focus_change.window = widget->window;
5300 fevent->focus_change.in = in;
5301 if (widget->window)
5302 g_object_ref (widget->window);
5303
5304 gtk_widget_send_focus_change (widget, fevent);
5305
5306 gdk_event_free (fevent);
5307 }
5308
5309 static gint
gtk_window_focus_in_event(GtkWidget * widget,GdkEventFocus * event)5310 gtk_window_focus_in_event (GtkWidget *widget,
5311 GdkEventFocus *event)
5312 {
5313 GtkWindow *window = GTK_WINDOW (widget);
5314
5315 /* It appears spurious focus in events can occur when
5316 * the window is hidden. So we'll just check to see if
5317 * the window is visible before actually handling the
5318 * event
5319 */
5320 if (gtk_widget_get_visible (widget))
5321 {
5322 _gtk_window_set_has_toplevel_focus (window, TRUE);
5323 _gtk_window_set_is_active (window, TRUE);
5324 }
5325
5326 return FALSE;
5327 }
5328
5329 static gint
gtk_window_focus_out_event(GtkWidget * widget,GdkEventFocus * event)5330 gtk_window_focus_out_event (GtkWidget *widget,
5331 GdkEventFocus *event)
5332 {
5333 GtkWindow *window = GTK_WINDOW (widget);
5334 gboolean auto_mnemonics;
5335
5336 _gtk_window_set_has_toplevel_focus (window, FALSE);
5337 _gtk_window_set_is_active (window, FALSE);
5338
5339 /* set the mnemonic-visible property to false */
5340 g_object_get (gtk_widget_get_settings (widget),
5341 "gtk-auto-mnemonics", &auto_mnemonics, NULL);
5342 if (auto_mnemonics)
5343 gtk_window_set_mnemonics_visible (window, FALSE);
5344
5345 return FALSE;
5346 }
5347
5348 static GdkAtom atom_rcfiles = GDK_NONE;
5349 static GdkAtom atom_iconthemes = GDK_NONE;
5350
5351 static void
send_client_message_to_embedded_windows(GtkWidget * widget,GdkAtom message_type)5352 send_client_message_to_embedded_windows (GtkWidget *widget,
5353 GdkAtom message_type)
5354 {
5355 GList *embedded_windows;
5356
5357 embedded_windows = g_object_get_qdata (G_OBJECT (widget), quark_gtk_embedded);
5358 if (embedded_windows)
5359 {
5360 GdkEvent *send_event = gdk_event_new (GDK_CLIENT_EVENT);
5361 int i;
5362
5363 for (i = 0; i < 5; i++)
5364 send_event->client.data.l[i] = 0;
5365 send_event->client.data_format = 32;
5366 send_event->client.message_type = message_type;
5367
5368 while (embedded_windows)
5369 {
5370 GdkNativeWindow xid = GDK_GPOINTER_TO_NATIVE_WINDOW(embedded_windows->data);
5371 gdk_event_send_client_message_for_display (gtk_widget_get_display (widget), send_event, xid);
5372 embedded_windows = embedded_windows->next;
5373 }
5374
5375 gdk_event_free (send_event);
5376 }
5377 }
5378
5379 static gint
gtk_window_client_event(GtkWidget * widget,GdkEventClient * event)5380 gtk_window_client_event (GtkWidget *widget,
5381 GdkEventClient *event)
5382 {
5383 if (!atom_rcfiles)
5384 {
5385 atom_rcfiles = gdk_atom_intern_static_string ("_GTK_READ_RCFILES");
5386 atom_iconthemes = gdk_atom_intern_static_string ("_GTK_LOAD_ICONTHEMES");
5387 }
5388
5389 if (event->message_type == atom_rcfiles)
5390 {
5391 send_client_message_to_embedded_windows (widget, atom_rcfiles);
5392 gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), FALSE);
5393 }
5394
5395 if (event->message_type == atom_iconthemes)
5396 {
5397 send_client_message_to_embedded_windows (widget, atom_iconthemes);
5398 _gtk_icon_theme_check_reload (gtk_widget_get_display (widget));
5399 }
5400
5401 return FALSE;
5402 }
5403
5404 static void
gtk_window_check_resize(GtkContainer * container)5405 gtk_window_check_resize (GtkContainer *container)
5406 {
5407 if (gtk_widget_get_visible (GTK_WIDGET (container)))
5408 gtk_window_move_resize (GTK_WINDOW (container));
5409 }
5410
5411 static gboolean
gtk_window_focus(GtkWidget * widget,GtkDirectionType direction)5412 gtk_window_focus (GtkWidget *widget,
5413 GtkDirectionType direction)
5414 {
5415 GtkBin *bin;
5416 GtkWindow *window;
5417 GtkContainer *container;
5418 GtkWidget *old_focus_child;
5419 GtkWidget *parent;
5420
5421 container = GTK_CONTAINER (widget);
5422 window = GTK_WINDOW (widget);
5423 bin = GTK_BIN (widget);
5424
5425 old_focus_child = container->focus_child;
5426
5427 /* We need a special implementation here to deal properly with wrapping
5428 * around in the tab chain without the danger of going into an
5429 * infinite loop.
5430 */
5431 if (old_focus_child)
5432 {
5433 if (gtk_widget_child_focus (old_focus_child, direction))
5434 return TRUE;
5435 }
5436
5437 if (window->focus_widget)
5438 {
5439 if (direction == GTK_DIR_LEFT ||
5440 direction == GTK_DIR_RIGHT ||
5441 direction == GTK_DIR_UP ||
5442 direction == GTK_DIR_DOWN)
5443 {
5444 return FALSE;
5445 }
5446
5447 /* Wrapped off the end, clear the focus setting for the toplpevel */
5448 parent = window->focus_widget->parent;
5449 while (parent)
5450 {
5451 gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
5452 parent = GTK_WIDGET (parent)->parent;
5453 }
5454
5455 gtk_window_set_focus (GTK_WINDOW (container), NULL);
5456 }
5457
5458 /* Now try to focus the first widget in the window */
5459 if (bin->child)
5460 {
5461 if (gtk_widget_child_focus (bin->child, direction))
5462 return TRUE;
5463 }
5464
5465 return FALSE;
5466 }
5467
5468 static void
gtk_window_real_set_focus(GtkWindow * window,GtkWidget * focus)5469 gtk_window_real_set_focus (GtkWindow *window,
5470 GtkWidget *focus)
5471 {
5472 GtkWidget *old_focus = window->focus_widget;
5473 gboolean had_default = FALSE;
5474 gboolean focus_had_default = FALSE;
5475 gboolean old_focus_had_default = FALSE;
5476
5477 if (old_focus)
5478 {
5479 g_object_ref (old_focus);
5480 g_object_freeze_notify (G_OBJECT (old_focus));
5481 old_focus_had_default = gtk_widget_has_default (old_focus);
5482 }
5483 if (focus)
5484 {
5485 g_object_ref (focus);
5486 g_object_freeze_notify (G_OBJECT (focus));
5487 focus_had_default = gtk_widget_has_default (focus);
5488 }
5489
5490 if (window->default_widget)
5491 had_default = gtk_widget_has_default (window->default_widget);
5492
5493 if (window->focus_widget)
5494 {
5495 if (gtk_widget_get_receives_default (window->focus_widget) &&
5496 (window->focus_widget != window->default_widget))
5497 {
5498 _gtk_widget_set_has_default (window->focus_widget, FALSE);
5499 gtk_widget_queue_draw (window->focus_widget);
5500
5501 if (window->default_widget)
5502 _gtk_widget_set_has_default (window->default_widget, TRUE);
5503 }
5504
5505 window->focus_widget = NULL;
5506
5507 if (window->has_focus)
5508 do_focus_change (old_focus, FALSE);
5509
5510 g_object_notify (G_OBJECT (old_focus), "is-focus");
5511 }
5512
5513 /* The above notifications may have set a new focus widget,
5514 * if so, we don't want to override it.
5515 */
5516 if (focus && !window->focus_widget)
5517 {
5518 window->focus_widget = focus;
5519
5520 if (gtk_widget_get_receives_default (window->focus_widget) &&
5521 (window->focus_widget != window->default_widget))
5522 {
5523 if (gtk_widget_get_can_default (window->focus_widget))
5524 _gtk_widget_set_has_default (window->focus_widget, TRUE);
5525
5526 if (window->default_widget)
5527 _gtk_widget_set_has_default (window->default_widget, FALSE);
5528 }
5529
5530 if (window->has_focus)
5531 do_focus_change (window->focus_widget, TRUE);
5532
5533 g_object_notify (G_OBJECT (window->focus_widget), "is-focus");
5534 }
5535
5536 /* If the default widget changed, a redraw will have been queued
5537 * on the old and new default widgets by gtk_window_set_default(), so
5538 * we only have to worry about the case where it didn't change.
5539 * We'll sometimes queue a draw twice on the new widget but that
5540 * is harmless.
5541 */
5542 if (window->default_widget &&
5543 (had_default != gtk_widget_has_default (window->default_widget)))
5544 gtk_widget_queue_draw (window->default_widget);
5545
5546 if (old_focus)
5547 {
5548 if (old_focus_had_default != gtk_widget_has_default (old_focus))
5549 gtk_widget_queue_draw (old_focus);
5550
5551 g_object_thaw_notify (G_OBJECT (old_focus));
5552 g_object_unref (old_focus);
5553 }
5554 if (focus)
5555 {
5556 if (focus_had_default != gtk_widget_has_default (focus))
5557 gtk_widget_queue_draw (focus);
5558
5559 g_object_thaw_notify (G_OBJECT (focus));
5560 g_object_unref (focus);
5561 }
5562 }
5563
5564 /**
5565 * _gtk_window_unset_focus_and_default:
5566 * @window: a #GtkWindow
5567 * @widget: a widget inside of @window
5568 *
5569 * Checks whether the focus and default widgets of @window are
5570 * @widget or a descendent of @widget, and if so, unset them.
5571 **/
5572 void
_gtk_window_unset_focus_and_default(GtkWindow * window,GtkWidget * widget)5573 _gtk_window_unset_focus_and_default (GtkWindow *window,
5574 GtkWidget *widget)
5575
5576 {
5577 GtkWidget *child;
5578
5579 g_object_ref (window);
5580 g_object_ref (widget);
5581
5582 if (GTK_CONTAINER (widget->parent)->focus_child == widget)
5583 {
5584 child = window->focus_widget;
5585
5586 while (child && child != widget)
5587 child = child->parent;
5588
5589 if (child == widget)
5590 gtk_window_set_focus (GTK_WINDOW (window), NULL);
5591 }
5592
5593 child = window->default_widget;
5594
5595 while (child && child != widget)
5596 child = child->parent;
5597
5598 if (child == widget)
5599 gtk_window_set_default (window, NULL);
5600
5601 g_object_unref (widget);
5602 g_object_unref (window);
5603 }
5604
5605 /*********************************
5606 * Functions related to resizing *
5607 *********************************/
5608
5609 /* This function doesn't constrain to geometry hints */
5610 static void
gtk_window_compute_configure_request_size(GtkWindow * window,guint * width,guint * height)5611 gtk_window_compute_configure_request_size (GtkWindow *window,
5612 guint *width,
5613 guint *height)
5614 {
5615 GtkRequisition requisition;
5616 GtkWindowGeometryInfo *info;
5617 GtkWidget *widget;
5618
5619 /* Preconditions:
5620 * - we've done a size request
5621 */
5622
5623 widget = GTK_WIDGET (window);
5624
5625 info = gtk_window_get_geometry_info (window, FALSE);
5626
5627 if (window->need_default_size)
5628 {
5629 gtk_widget_get_child_requisition (widget, &requisition);
5630
5631 /* Default to requisition */
5632 *width = requisition.width;
5633 *height = requisition.height;
5634
5635 /* If window is empty so requests 0, default to random nonzero size */
5636 if (*width == 0 && *height == 0)
5637 {
5638 *width = 200;
5639 *height = 200;
5640 }
5641
5642 /* Override requisition with default size */
5643
5644 if (info)
5645 {
5646 gint base_width = 0;
5647 gint base_height = 0;
5648 gint min_width = 0;
5649 gint min_height = 0;
5650 gint width_inc = 1;
5651 gint height_inc = 1;
5652
5653 if (info->default_is_geometry &&
5654 (info->default_width > 0 || info->default_height > 0))
5655 {
5656 GdkGeometry geometry;
5657 guint flags;
5658
5659 gtk_window_compute_hints (window, &geometry, &flags);
5660
5661 if (flags & GDK_HINT_BASE_SIZE)
5662 {
5663 base_width = geometry.base_width;
5664 base_height = geometry.base_height;
5665 }
5666 if (flags & GDK_HINT_MIN_SIZE)
5667 {
5668 min_width = geometry.min_width;
5669 min_height = geometry.min_height;
5670 }
5671 if (flags & GDK_HINT_RESIZE_INC)
5672 {
5673 width_inc = geometry.width_inc;
5674 height_inc = geometry.height_inc;
5675 }
5676 }
5677
5678 if (info->default_width > 0)
5679 *width = MAX (info->default_width * width_inc + base_width, min_width);
5680
5681 if (info->default_height > 0)
5682 *height = MAX (info->default_height * height_inc + base_height, min_height);
5683 }
5684 }
5685 else
5686 {
5687 /* Default to keeping current size */
5688 *width = widget->allocation.width;
5689 *height = widget->allocation.height;
5690 }
5691
5692 /* Override any size with gtk_window_resize() values */
5693 if (info)
5694 {
5695 if (info->resize_width > 0)
5696 *width = info->resize_width;
5697
5698 if (info->resize_height > 0)
5699 *height = info->resize_height;
5700 }
5701
5702 /* Don't ever request zero width or height, its not supported by
5703 gdk. The size allocation code will round it to 1 anyway but if
5704 we do it then the value returned from this function will is
5705 not comparable to the size allocation read from the GtkWindow. */
5706 *width = MAX (*width, 1);
5707 *height = MAX (*height, 1);
5708 }
5709
5710 static GtkWindowPosition
get_effective_position(GtkWindow * window)5711 get_effective_position (GtkWindow *window)
5712 {
5713 GtkWindowPosition pos = window->position;
5714
5715 if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
5716 (window->transient_parent == NULL ||
5717 !gtk_widget_get_mapped (GTK_WIDGET (window->transient_parent))))
5718 pos = GTK_WIN_POS_NONE;
5719
5720 return pos;
5721 }
5722
5723 static int
get_center_monitor_of_window(GtkWindow * window)5724 get_center_monitor_of_window (GtkWindow *window)
5725 {
5726 /* We could try to sort out the relative positions of the monitors and
5727 * stuff, or we could just be losers and assume you have a row
5728 * or column of monitors.
5729 */
5730 return gdk_screen_get_n_monitors (gtk_window_check_screen (window)) / 2;
5731 }
5732
5733 static int
get_monitor_containing_pointer(GtkWindow * window)5734 get_monitor_containing_pointer (GtkWindow *window)
5735 {
5736 gint px, py;
5737 gint monitor_num;
5738 GdkScreen *window_screen;
5739 GdkScreen *pointer_screen;
5740
5741 window_screen = gtk_window_check_screen (window);
5742 gdk_display_get_pointer (gdk_screen_get_display (window_screen),
5743 &pointer_screen,
5744 &px, &py, NULL);
5745
5746 if (pointer_screen == window_screen)
5747 monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py);
5748 else
5749 monitor_num = -1;
5750
5751 return monitor_num;
5752 }
5753
5754 static void
center_window_on_monitor(GtkWindow * window,gint w,gint h,gint * x,gint * y)5755 center_window_on_monitor (GtkWindow *window,
5756 gint w,
5757 gint h,
5758 gint *x,
5759 gint *y)
5760 {
5761 GdkRectangle monitor;
5762 int monitor_num;
5763
5764 monitor_num = get_monitor_containing_pointer (window);
5765
5766 if (monitor_num == -1)
5767 monitor_num = get_center_monitor_of_window (window);
5768
5769 gdk_screen_get_monitor_geometry (gtk_window_check_screen (window),
5770 monitor_num, &monitor);
5771
5772 *x = (monitor.width - w) / 2 + monitor.x;
5773 *y = (monitor.height - h) / 2 + monitor.y;
5774
5775 /* Be sure we aren't off the monitor, ignoring _NET_WM_STRUT
5776 * and WM decorations.
5777 */
5778 if (*x < monitor.x)
5779 *x = monitor.x;
5780 if (*y < monitor.y)
5781 *y = monitor.y;
5782 }
5783
5784 static void
clamp(gint * base,gint extent,gint clamp_base,gint clamp_extent)5785 clamp (gint *base,
5786 gint extent,
5787 gint clamp_base,
5788 gint clamp_extent)
5789 {
5790 if (extent > clamp_extent)
5791 /* Center */
5792 *base = clamp_base + clamp_extent/2 - extent/2;
5793 else if (*base < clamp_base)
5794 *base = clamp_base;
5795 else if (*base + extent > clamp_base + clamp_extent)
5796 *base = clamp_base + clamp_extent - extent;
5797 }
5798
5799 static void
clamp_window_to_rectangle(gint * x,gint * y,gint w,gint h,const GdkRectangle * rect)5800 clamp_window_to_rectangle (gint *x,
5801 gint *y,
5802 gint w,
5803 gint h,
5804 const GdkRectangle *rect)
5805 {
5806 #ifdef DEBUGGING_OUTPUT
5807 g_print ("%s: %+d%+d %dx%d: %+d%+d: %dx%d", G_STRFUNC, rect->x, rect->y, rect->width, rect->height, *x, *y, w, h);
5808 #endif
5809
5810 /* If it is too large, center it. If it fits on the monitor but is
5811 * partially outside, move it to the closest edge. Do this
5812 * separately in x and y directions.
5813 */
5814 clamp (x, w, rect->x, rect->width);
5815 clamp (y, h, rect->y, rect->height);
5816 #ifdef DEBUGGING_OUTPUT
5817 g_print (" ==> %+d%+d: %dx%d\n", *x, *y, w, h);
5818 #endif
5819 }
5820
5821
5822 static void
gtk_window_compute_configure_request(GtkWindow * window,GdkRectangle * request,GdkGeometry * geometry,guint * flags)5823 gtk_window_compute_configure_request (GtkWindow *window,
5824 GdkRectangle *request,
5825 GdkGeometry *geometry,
5826 guint *flags)
5827 {
5828 GdkGeometry new_geometry;
5829 guint new_flags;
5830 int w, h;
5831 GtkWidget *widget;
5832 GtkWindowPosition pos;
5833 GtkWidget *parent_widget;
5834 GtkWindowGeometryInfo *info;
5835 GdkScreen *screen;
5836 int x, y;
5837
5838 widget = GTK_WIDGET (window);
5839
5840 screen = gtk_window_check_screen (window);
5841
5842 gtk_widget_size_request (widget, NULL);
5843 gtk_window_compute_configure_request_size (window, (guint *)&w, (guint *)&h);
5844
5845 gtk_window_compute_hints (window, &new_geometry, &new_flags);
5846 gtk_window_constrain_size (window,
5847 &new_geometry, new_flags,
5848 w, h,
5849 &w, &h);
5850
5851 parent_widget = (GtkWidget*) window->transient_parent;
5852
5853 pos = get_effective_position (window);
5854 info = gtk_window_get_geometry_info (window, FALSE);
5855
5856 /* by default, don't change position requested */
5857 if (info)
5858 {
5859 x = info->last.configure_request.x;
5860 y = info->last.configure_request.y;
5861 }
5862 else
5863 {
5864 x = 0;
5865 y = 0;
5866 }
5867
5868
5869 if (window->need_default_position)
5870 {
5871
5872 /* FIXME this all interrelates with window gravity.
5873 * For most of them I think we want to set GRAVITY_CENTER.
5874 *
5875 * Not sure how to go about that.
5876 */
5877
5878 switch (pos)
5879 {
5880 /* here we are only handling CENTER_ALWAYS
5881 * as it relates to default positioning,
5882 * where it's equivalent to simply CENTER
5883 */
5884 case GTK_WIN_POS_CENTER_ALWAYS:
5885 case GTK_WIN_POS_CENTER:
5886 center_window_on_monitor (window, w, h, &x, &y);
5887 break;
5888
5889 case GTK_WIN_POS_CENTER_ON_PARENT:
5890 {
5891 gint monitor_num;
5892 GdkRectangle monitor;
5893 gint ox, oy;
5894
5895 g_assert (gtk_widget_get_mapped (parent_widget)); /* established earlier */
5896
5897 if (parent_widget->window != NULL)
5898 monitor_num = gdk_screen_get_monitor_at_window (screen,
5899 parent_widget->window);
5900 else
5901 monitor_num = -1;
5902
5903 gdk_window_get_origin (parent_widget->window,
5904 &ox, &oy);
5905
5906 x = ox + (parent_widget->allocation.width - w) / 2;
5907 y = oy + (parent_widget->allocation.height - h) / 2;
5908
5909 /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
5910 * WM decorations. If parent wasn't on a monitor, just
5911 * give up.
5912 */
5913 if (monitor_num >= 0)
5914 {
5915 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
5916 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
5917 }
5918 }
5919 break;
5920
5921 case GTK_WIN_POS_MOUSE:
5922 {
5923 gint screen_width = gdk_screen_get_width (screen);
5924 gint screen_height = gdk_screen_get_height (screen);
5925 gint monitor_num;
5926 GdkRectangle monitor;
5927 GdkScreen *pointer_screen;
5928 gint px, py;
5929
5930 gdk_display_get_pointer (gdk_screen_get_display (screen),
5931 &pointer_screen,
5932 &px, &py, NULL);
5933
5934 if (pointer_screen == screen)
5935 monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
5936 else
5937 monitor_num = -1;
5938
5939 x = px - w / 2;
5940 y = py - h / 2;
5941 x = CLAMP (x, 0, screen_width - w);
5942 y = CLAMP (y, 0, screen_height - h);
5943
5944 /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
5945 * WM decorations. Don't try to figure out what's going
5946 * on if the mouse wasn't inside a monitor.
5947 */
5948 if (monitor_num >= 0)
5949 {
5950 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
5951 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
5952 }
5953 }
5954 break;
5955
5956 default:
5957 break;
5958 }
5959 } /* if (window->need_default_position) */
5960
5961 if (window->need_default_position && info &&
5962 info->initial_pos_set)
5963 {
5964 x = info->initial_x;
5965 y = info->initial_y;
5966 gtk_window_constrain_position (window, w, h, &x, &y);
5967 }
5968
5969 request->x = x;
5970 request->y = y;
5971 request->width = w;
5972 request->height = h;
5973
5974 if (geometry)
5975 *geometry = new_geometry;
5976 if (flags)
5977 *flags = new_flags;
5978 }
5979
5980 static void
gtk_window_constrain_position(GtkWindow * window,gint new_width,gint new_height,gint * x,gint * y)5981 gtk_window_constrain_position (GtkWindow *window,
5982 gint new_width,
5983 gint new_height,
5984 gint *x,
5985 gint *y)
5986 {
5987 /* See long comments in gtk_window_move_resize()
5988 * on when it's safe to call this function.
5989 */
5990 if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
5991 {
5992 gint center_x, center_y;
5993
5994 center_window_on_monitor (window, new_width, new_height, ¢er_x, ¢er_y);
5995
5996 *x = center_x;
5997 *y = center_y;
5998 }
5999 }
6000
6001 static void
gtk_window_move_resize(GtkWindow * window)6002 gtk_window_move_resize (GtkWindow *window)
6003 {
6004 /* Overview:
6005 *
6006 * First we determine whether any information has changed that would
6007 * cause us to revise our last configure request. If we would send
6008 * a different configure request from last time, then
6009 * configure_request_size_changed = TRUE or
6010 * configure_request_pos_changed = TRUE. configure_request_size_changed
6011 * may be true due to new hints, a gtk_window_resize(), or whatever.
6012 * configure_request_pos_changed may be true due to gtk_window_set_position()
6013 * or gtk_window_move().
6014 *
6015 * If the configure request has changed, we send off a new one. To
6016 * ensure GTK+ invariants are maintained (resize queue does what it
6017 * should), we go ahead and size_allocate the requested size in this
6018 * function.
6019 *
6020 * If the configure request has not changed, we don't ever resend
6021 * it, because it could mean fighting the user or window manager.
6022 *
6023 *
6024 * To prepare the configure request, we come up with a base size/pos:
6025 * - the one from gtk_window_move()/gtk_window_resize()
6026 * - else default_width, default_height if we haven't ever
6027 * been mapped
6028 * - else the size request if we haven't ever been mapped,
6029 * as a substitute default size
6030 * - else the current size of the window, as received from
6031 * configure notifies (i.e. the current allocation)
6032 *
6033 * If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
6034 * the position request to be centered.
6035 */
6036 GtkWidget *widget;
6037 GtkContainer *container;
6038 GtkWindowGeometryInfo *info;
6039 GdkGeometry new_geometry;
6040 guint new_flags;
6041 GdkRectangle new_request;
6042 gboolean configure_request_size_changed;
6043 gboolean configure_request_pos_changed;
6044 gboolean hints_changed; /* do we need to send these again */
6045 GtkWindowLastGeometryInfo saved_last_info;
6046
6047 widget = GTK_WIDGET (window);
6048 container = GTK_CONTAINER (widget);
6049 info = gtk_window_get_geometry_info (window, TRUE);
6050
6051 configure_request_size_changed = FALSE;
6052 configure_request_pos_changed = FALSE;
6053
6054 gtk_window_compute_configure_request (window, &new_request,
6055 &new_geometry, &new_flags);
6056
6057 /* This check implies the invariant that we never set info->last
6058 * without setting the hints and sending off a configure request.
6059 *
6060 * If we change info->last without sending the request, we may
6061 * miss a request.
6062 */
6063 if (info->last.configure_request.x != new_request.x ||
6064 info->last.configure_request.y != new_request.y)
6065 configure_request_pos_changed = TRUE;
6066
6067 if ((info->last.configure_request.width != new_request.width ||
6068 info->last.configure_request.height != new_request.height))
6069 configure_request_size_changed = TRUE;
6070
6071 hints_changed = FALSE;
6072
6073 if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
6074 &new_geometry, new_flags))
6075 {
6076 hints_changed = TRUE;
6077 }
6078
6079 /* Position Constraints
6080 * ====================
6081 *
6082 * POS_CENTER_ALWAYS is conceptually a constraint rather than
6083 * a default. The other POS_ values are used only when the
6084 * window is shown, not after that.
6085 *
6086 * However, we can't implement a position constraint as
6087 * "anytime the window size changes, center the window"
6088 * because this may well end up fighting the WM or user. In
6089 * fact it gets in an infinite loop with at least one WM.
6090 *
6091 * Basically, applications are in no way in a position to
6092 * constrain the position of a window, with one exception:
6093 * override redirect windows. (Really the intended purpose
6094 * of CENTER_ALWAYS anyhow, I would think.)
6095 *
6096 * So the way we implement this "constraint" is to say that when WE
6097 * cause a move or resize, i.e. we make a configure request changing
6098 * window size, we recompute the CENTER_ALWAYS position to reflect
6099 * the new window size, and include it in our request. Also, if we
6100 * just turned on CENTER_ALWAYS we snap to center with a new
6101 * request. Otherwise, if we are just NOTIFIED of a move or resize
6102 * done by someone else e.g. the window manager, we do NOT send a
6103 * new configure request.
6104 *
6105 * For override redirect windows, this works fine; all window
6106 * sizes are from our configure requests. For managed windows,
6107 * it is at least semi-sane, though who knows what the
6108 * app author is thinking.
6109 */
6110
6111 /* This condition should be kept in sync with the condition later on
6112 * that determines whether we send a configure request. i.e. we
6113 * should do this position constraining anytime we were going to
6114 * send a configure request anyhow, plus when constraints have
6115 * changed.
6116 */
6117 if (configure_request_pos_changed ||
6118 configure_request_size_changed ||
6119 hints_changed ||
6120 info->position_constraints_changed)
6121 {
6122 /* We request the constrained position if:
6123 * - we were changing position, and need to clamp
6124 * the change to the constraint
6125 * - we're changing the size anyway
6126 * - set_position() was called to toggle CENTER_ALWAYS on
6127 */
6128
6129 gtk_window_constrain_position (window,
6130 new_request.width,
6131 new_request.height,
6132 &new_request.x,
6133 &new_request.y);
6134
6135 /* Update whether we need to request a move */
6136 if (info->last.configure_request.x != new_request.x ||
6137 info->last.configure_request.y != new_request.y)
6138 configure_request_pos_changed = TRUE;
6139 else
6140 configure_request_pos_changed = FALSE;
6141 }
6142
6143 #if 0
6144 if (window->type == GTK_WINDOW_TOPLEVEL)
6145 {
6146 int notify_x, notify_y;
6147
6148 /* this is the position from the last configure notify */
6149 gdk_window_get_position (widget->window, ¬ify_x, ¬ify_y);
6150
6151 g_message ("--- %s ---\n"
6152 "last : %d,%d\t%d x %d\n"
6153 "this : %d,%d\t%d x %d\n"
6154 "alloc : %d,%d\t%d x %d\n"
6155 "req : \t%d x %d\n"
6156 "resize: \t%d x %d\n"
6157 "size_changed: %d pos_changed: %d hints_changed: %d\n"
6158 "configure_notify_received: %d\n"
6159 "configure_request_count: %d\n"
6160 "position_constraints_changed: %d\n",
6161 window->title ? window->title : "(no title)",
6162 info->last.configure_request.x,
6163 info->last.configure_request.y,
6164 info->last.configure_request.width,
6165 info->last.configure_request.height,
6166 new_request.x,
6167 new_request.y,
6168 new_request.width,
6169 new_request.height,
6170 notify_x, notify_y,
6171 widget->allocation.width,
6172 widget->allocation.height,
6173 widget->requisition.width,
6174 widget->requisition.height,
6175 info->resize_width,
6176 info->resize_height,
6177 configure_request_pos_changed,
6178 configure_request_size_changed,
6179 hints_changed,
6180 window->configure_notify_received,
6181 window->configure_request_count,
6182 info->position_constraints_changed);
6183 }
6184 #endif
6185
6186 saved_last_info = info->last;
6187 info->last.geometry = new_geometry;
6188 info->last.flags = new_flags;
6189 info->last.configure_request = new_request;
6190
6191 /* need to set PPosition so the WM will look at our position,
6192 * but we don't want to count PPosition coming and going as a hints
6193 * change for future iterations. So we saved info->last prior to
6194 * this.
6195 */
6196
6197 /* Also, if the initial position was explicitly set, then we always
6198 * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
6199 * work.
6200 */
6201
6202 /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
6203 * this is an initial map
6204 */
6205
6206 if ((configure_request_pos_changed ||
6207 info->initial_pos_set ||
6208 (window->need_default_position &&
6209 get_effective_position (window) != GTK_WIN_POS_NONE)) &&
6210 (new_flags & GDK_HINT_POS) == 0)
6211 {
6212 new_flags |= GDK_HINT_POS;
6213 hints_changed = TRUE;
6214 }
6215
6216 /* Set hints if necessary
6217 */
6218 if (hints_changed)
6219 gdk_window_set_geometry_hints (widget->window,
6220 &new_geometry,
6221 new_flags);
6222
6223 /* handle resizing/moving and widget tree allocation
6224 */
6225 if (window->configure_notify_received)
6226 {
6227 GtkAllocation allocation;
6228
6229 /* If we have received a configure event since
6230 * the last time in this function, we need to
6231 * accept our new size and size_allocate child widgets.
6232 * (see gtk_window_configure_event() for more details).
6233 *
6234 * 1 or more configure notifies may have been received.
6235 * Also, configure_notify_received will only be TRUE
6236 * if all expected configure notifies have been received
6237 * (one per configure request), as an optimization.
6238 *
6239 */
6240 window->configure_notify_received = FALSE;
6241
6242 /* gtk_window_configure_event() filled in widget->allocation */
6243 allocation = widget->allocation;
6244 gtk_widget_size_allocate (widget, &allocation);
6245
6246 gdk_window_process_updates (widget->window, TRUE);
6247
6248 gdk_window_configure_finished (widget->window);
6249
6250 /* If the configure request changed, it means that
6251 * we either:
6252 * 1) coincidentally changed hints or widget properties
6253 * impacting the configure request before getting
6254 * a configure notify, or
6255 * 2) some broken widget is changing its size request
6256 * during size allocation, resulting in
6257 * a false appearance of changed configure request.
6258 *
6259 * For 1), we could just go ahead and ask for the
6260 * new size right now, but doing that for 2)
6261 * might well be fighting the user (and can even
6262 * trigger a loop). Since we really don't want to
6263 * do that, we requeue a resize in hopes that
6264 * by the time it gets handled, the child has seen
6265 * the light and is willing to go along with the
6266 * new size. (this happens for the zvt widget, since
6267 * the size_allocate() above will have stored the
6268 * requisition corresponding to the new size in the
6269 * zvt widget)
6270 *
6271 * This doesn't buy us anything for 1), but it shouldn't
6272 * hurt us too badly, since it is what would have
6273 * happened if we had gotten the configure event before
6274 * the new size had been set.
6275 */
6276
6277 if (configure_request_size_changed ||
6278 configure_request_pos_changed)
6279 {
6280 /* Don't change the recorded last info after all, because we
6281 * haven't actually updated to the new info yet - we decided
6282 * to postpone our configure request until later.
6283 */
6284 info->last = saved_last_info;
6285
6286 gtk_widget_queue_resize_no_redraw (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
6287 }
6288
6289 return; /* Bail out, we didn't really process the move/resize */
6290 }
6291 else if ((configure_request_size_changed || hints_changed) &&
6292 (widget->allocation.width != new_request.width ||
6293 widget->allocation.height != new_request.height))
6294
6295 {
6296 /* We are in one of the following situations:
6297 * A. configure_request_size_changed
6298 * our requisition has changed and we need a different window size,
6299 * so we request it from the window manager.
6300 * B. !configure_request_size_changed && hints_changed
6301 * the window manager rejects our size, but we have just changed the
6302 * window manager hints, so there's a chance our request will
6303 * be honoured this time, so we try again.
6304 *
6305 * However, if the new requisition is the same as the current allocation,
6306 * we don't request it again, since we won't get a ConfigureNotify back from
6307 * the window manager unless it decides to change our requisition. If
6308 * we don't get the ConfigureNotify back, the resize queue will never be run.
6309 */
6310
6311 /* Now send the configure request */
6312 if (configure_request_pos_changed)
6313 {
6314 if (window->frame)
6315 {
6316 gdk_window_move_resize (window->frame,
6317 new_request.x - window->frame_left,
6318 new_request.y - window->frame_top,
6319 new_request.width + window->frame_left + window->frame_right,
6320 new_request.height + window->frame_top + window->frame_bottom);
6321 gdk_window_resize (widget->window,
6322 new_request.width, new_request.height);
6323 }
6324 else
6325 gdk_window_move_resize (widget->window,
6326 new_request.x, new_request.y,
6327 new_request.width, new_request.height);
6328 }
6329 else /* only size changed */
6330 {
6331 if (window->frame)
6332 gdk_window_resize (window->frame,
6333 new_request.width + window->frame_left + window->frame_right,
6334 new_request.height + window->frame_top + window->frame_bottom);
6335 gdk_window_resize (widget->window,
6336 new_request.width, new_request.height);
6337 }
6338
6339 if (window->type == GTK_WINDOW_POPUP)
6340 {
6341 GtkAllocation allocation;
6342
6343 /* Directly size allocate for override redirect (popup) windows. */
6344 allocation.x = 0;
6345 allocation.y = 0;
6346 allocation.width = new_request.width;
6347 allocation.height = new_request.height;
6348
6349 gtk_widget_size_allocate (widget, &allocation);
6350
6351 gdk_window_process_updates (widget->window, TRUE);
6352
6353 if (container->resize_mode == GTK_RESIZE_QUEUE)
6354 gtk_widget_queue_draw (widget);
6355 }
6356 else
6357 {
6358 /* Increment the number of have-not-yet-received-notify requests */
6359 window->configure_request_count += 1;
6360 gdk_window_freeze_toplevel_updates_libgtk_only (widget->window);
6361
6362 /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
6363 * configure event in response to our resizing request.
6364 * the configure event will cause a new resize with
6365 * ->configure_notify_received=TRUE.
6366 * until then, we want to
6367 * - discard expose events
6368 * - coalesce resizes for our children
6369 * - defer any window resizes until the configure event arrived
6370 * to achieve this, we queue a resize for the window, but remove its
6371 * resizing handler, so resizing will not be handled from the next
6372 * idle handler but when the configure event arrives.
6373 *
6374 * FIXME: we should also dequeue the pending redraws here, since
6375 * we handle those ourselves upon ->configure_notify_received==TRUE.
6376 */
6377 if (container->resize_mode == GTK_RESIZE_QUEUE)
6378 {
6379 gtk_widget_queue_resize_no_redraw (widget);
6380 _gtk_container_dequeue_resize_handler (container);
6381 }
6382 }
6383 }
6384 else
6385 {
6386 /* Handle any position changes.
6387 */
6388 if (configure_request_pos_changed)
6389 {
6390 if (window->frame)
6391 {
6392 gdk_window_move (window->frame,
6393 new_request.x - window->frame_left,
6394 new_request.y - window->frame_top);
6395 }
6396 else
6397 gdk_window_move (widget->window,
6398 new_request.x, new_request.y);
6399 }
6400
6401 /* And run the resize queue.
6402 */
6403 gtk_container_resize_children (container);
6404 }
6405
6406 /* We have now processed a move/resize since the last position
6407 * constraint change, setting of the initial position, or resize.
6408 * (Not resetting these flags here can lead to infinite loops for
6409 * GTK_RESIZE_IMMEDIATE containers)
6410 */
6411 info->position_constraints_changed = FALSE;
6412 info->initial_pos_set = FALSE;
6413 info->resize_width = -1;
6414 info->resize_height = -1;
6415 }
6416
6417 /* Compare two sets of Geometry hints for equality.
6418 */
6419 static gboolean
gtk_window_compare_hints(GdkGeometry * geometry_a,guint flags_a,GdkGeometry * geometry_b,guint flags_b)6420 gtk_window_compare_hints (GdkGeometry *geometry_a,
6421 guint flags_a,
6422 GdkGeometry *geometry_b,
6423 guint flags_b)
6424 {
6425 if (flags_a != flags_b)
6426 return FALSE;
6427
6428 if ((flags_a & GDK_HINT_MIN_SIZE) &&
6429 (geometry_a->min_width != geometry_b->min_width ||
6430 geometry_a->min_height != geometry_b->min_height))
6431 return FALSE;
6432
6433 if ((flags_a & GDK_HINT_MAX_SIZE) &&
6434 (geometry_a->max_width != geometry_b->max_width ||
6435 geometry_a->max_height != geometry_b->max_height))
6436 return FALSE;
6437
6438 if ((flags_a & GDK_HINT_BASE_SIZE) &&
6439 (geometry_a->base_width != geometry_b->base_width ||
6440 geometry_a->base_height != geometry_b->base_height))
6441 return FALSE;
6442
6443 if ((flags_a & GDK_HINT_ASPECT) &&
6444 (geometry_a->min_aspect != geometry_b->min_aspect ||
6445 geometry_a->max_aspect != geometry_b->max_aspect))
6446 return FALSE;
6447
6448 if ((flags_a & GDK_HINT_RESIZE_INC) &&
6449 (geometry_a->width_inc != geometry_b->width_inc ||
6450 geometry_a->height_inc != geometry_b->height_inc))
6451 return FALSE;
6452
6453 if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
6454 geometry_a->win_gravity != geometry_b->win_gravity)
6455 return FALSE;
6456
6457 return TRUE;
6458 }
6459
6460 void
_gtk_window_constrain_size(GtkWindow * window,gint width,gint height,gint * new_width,gint * new_height)6461 _gtk_window_constrain_size (GtkWindow *window,
6462 gint width,
6463 gint height,
6464 gint *new_width,
6465 gint *new_height)
6466 {
6467 GtkWindowGeometryInfo *info;
6468
6469 g_return_if_fail (GTK_IS_WINDOW (window));
6470
6471 info = window->geometry_info;
6472 if (info)
6473 {
6474 GdkWindowHints flags = info->last.flags;
6475 GdkGeometry *geometry = &info->last.geometry;
6476
6477 gtk_window_constrain_size (window,
6478 geometry,
6479 flags,
6480 width,
6481 height,
6482 new_width,
6483 new_height);
6484 }
6485 }
6486
6487 static void
gtk_window_constrain_size(GtkWindow * window,GdkGeometry * geometry,guint flags,gint width,gint height,gint * new_width,gint * new_height)6488 gtk_window_constrain_size (GtkWindow *window,
6489 GdkGeometry *geometry,
6490 guint flags,
6491 gint width,
6492 gint height,
6493 gint *new_width,
6494 gint *new_height)
6495 {
6496 gdk_window_constrain_size (geometry, flags, width, height,
6497 new_width, new_height);
6498 }
6499
6500 /* Compute the set of geometry hints and flags for a window
6501 * based on the application set geometry, and requisiition
6502 * of the window. gtk_widget_size_request() must have been
6503 * called first.
6504 */
6505 static void
gtk_window_compute_hints(GtkWindow * window,GdkGeometry * new_geometry,guint * new_flags)6506 gtk_window_compute_hints (GtkWindow *window,
6507 GdkGeometry *new_geometry,
6508 guint *new_flags)
6509 {
6510 GtkWidget *widget;
6511 gint extra_width = 0;
6512 gint extra_height = 0;
6513 GtkWindowGeometryInfo *geometry_info;
6514 GtkRequisition requisition;
6515
6516 widget = GTK_WIDGET (window);
6517
6518 gtk_widget_get_child_requisition (widget, &requisition);
6519 geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
6520
6521 if (geometry_info)
6522 {
6523 *new_flags = geometry_info->mask;
6524 *new_geometry = geometry_info->geometry;
6525 }
6526 else
6527 {
6528 *new_flags = 0;
6529 }
6530
6531 if (geometry_info && geometry_info->widget)
6532 {
6533 GtkRequisition child_requisition;
6534
6535 /* FIXME: This really isn't right. It gets the min size wrong and forces
6536 * callers to do horrible hacks like set a huge usize on the child requisition
6537 * to get the base size right. We really want to find the answers to:
6538 *
6539 * - If the geometry widget was infinitely big, how much extra space
6540 * would be needed for the stuff around it.
6541 *
6542 * - If the geometry widget was infinitely small, how big would the
6543 * window still have to be.
6544 *
6545 * Finding these answers would be a bit of a mess here. (Bug #68668)
6546 */
6547 gtk_widget_get_child_requisition (geometry_info->widget, &child_requisition);
6548
6549 extra_width = widget->requisition.width - child_requisition.width;
6550 extra_height = widget->requisition.height - child_requisition.height;
6551 }
6552
6553 /* We don't want to set GDK_HINT_POS in here, we just set it
6554 * in gtk_window_move_resize() when we want the position
6555 * honored.
6556 */
6557
6558 if (*new_flags & GDK_HINT_BASE_SIZE)
6559 {
6560 new_geometry->base_width += extra_width;
6561 new_geometry->base_height += extra_height;
6562 }
6563 else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
6564 (*new_flags & GDK_HINT_RESIZE_INC) &&
6565 ((extra_width != 0) || (extra_height != 0)))
6566 {
6567 *new_flags |= GDK_HINT_BASE_SIZE;
6568
6569 new_geometry->base_width = extra_width;
6570 new_geometry->base_height = extra_height;
6571 }
6572
6573 if (*new_flags & GDK_HINT_MIN_SIZE)
6574 {
6575 if (new_geometry->min_width < 0)
6576 new_geometry->min_width = requisition.width;
6577 else
6578 new_geometry->min_width += extra_width;
6579
6580 if (new_geometry->min_height < 0)
6581 new_geometry->min_height = requisition.height;
6582 else
6583 new_geometry->min_height += extra_height;
6584 }
6585 else if (!window->allow_shrink)
6586 {
6587 *new_flags |= GDK_HINT_MIN_SIZE;
6588
6589 new_geometry->min_width = requisition.width;
6590 new_geometry->min_height = requisition.height;
6591 }
6592
6593 if (*new_flags & GDK_HINT_MAX_SIZE)
6594 {
6595 if (new_geometry->max_width < 0)
6596 new_geometry->max_width = requisition.width;
6597 else
6598 new_geometry->max_width += extra_width;
6599
6600 if (new_geometry->max_height < 0)
6601 new_geometry->max_height = requisition.height;
6602 else
6603 new_geometry->max_height += extra_height;
6604 }
6605 else if (!window->allow_grow)
6606 {
6607 *new_flags |= GDK_HINT_MAX_SIZE;
6608
6609 new_geometry->max_width = requisition.width;
6610 new_geometry->max_height = requisition.height;
6611 }
6612
6613 *new_flags |= GDK_HINT_WIN_GRAVITY;
6614 new_geometry->win_gravity = window->gravity;
6615 }
6616
6617 /***********************
6618 * Redrawing functions *
6619 ***********************/
6620
6621 static void
gtk_window_paint(GtkWidget * widget,GdkRectangle * area)6622 gtk_window_paint (GtkWidget *widget,
6623 GdkRectangle *area)
6624 {
6625 gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
6626 GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
6627 }
6628
6629 static gint
gtk_window_expose(GtkWidget * widget,GdkEventExpose * event)6630 gtk_window_expose (GtkWidget *widget,
6631 GdkEventExpose *event)
6632 {
6633 if (!gtk_widget_get_app_paintable (widget))
6634 gtk_window_paint (widget, &event->area);
6635
6636 if (GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event)
6637 return GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event (widget, event);
6638
6639 return FALSE;
6640 }
6641
6642 /**
6643 * gtk_window_set_has_frame:
6644 * @window: a #GtkWindow
6645 * @setting: a boolean
6646 *
6647 * (Note: this is a special-purpose function for the framebuffer port,
6648 * that causes GTK+ to draw its own window border. For most applications,
6649 * you want gtk_window_set_decorated() instead, which tells the window
6650 * manager whether to draw the window border.)
6651 *
6652 * If this function is called on a window with setting of %TRUE, before
6653 * it is realized or showed, it will have a "frame" window around
6654 * @window->window, accessible in @window->frame. Using the signal
6655 * frame_event you can receive all events targeted at the frame.
6656 *
6657 * This function is used by the linux-fb port to implement managed
6658 * windows, but it could conceivably be used by X-programs that
6659 * want to do their own window decorations.
6660 *
6661 * Deprecated: 2.24: This function will be removed in GTK+ 3
6662 **/
6663 void
gtk_window_set_has_frame(GtkWindow * window,gboolean setting)6664 gtk_window_set_has_frame (GtkWindow *window,
6665 gboolean setting)
6666 {
6667 g_return_if_fail (GTK_IS_WINDOW (window));
6668 g_return_if_fail (!gtk_widget_get_realized (GTK_WIDGET (window)));
6669
6670 window->has_frame = setting != FALSE;
6671 }
6672
6673 /**
6674 * gtk_window_get_has_frame:
6675 * @window: a #GtkWindow
6676 *
6677 * Accessor for whether the window has a frame window exterior to
6678 * @window->window. Gets the value set by gtk_window_set_has_frame ().
6679 *
6680 * Return value: %TRUE if a frame has been added to the window
6681 * via gtk_window_set_has_frame().
6682 *
6683 * Deprecated: 2.24: This function will be removed in GTK+ 3
6684 **/
6685 gboolean
gtk_window_get_has_frame(GtkWindow * window)6686 gtk_window_get_has_frame (GtkWindow *window)
6687 {
6688 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
6689
6690 return window->has_frame;
6691 }
6692
6693 /**
6694 * gtk_window_set_frame_dimensions:
6695 * @window: a #GtkWindow that has a frame
6696 * @left: The width of the left border
6697 * @top: The height of the top border
6698 * @right: The width of the right border
6699 * @bottom: The height of the bottom border
6700 *
6701 * (Note: this is a special-purpose function intended for the framebuffer
6702 * port; see gtk_window_set_has_frame(). It will have no effect on the
6703 * window border drawn by the window manager, which is the normal
6704 * case when using the X Window system.)
6705 *
6706 * For windows with frames (see gtk_window_set_has_frame()) this function
6707 * can be used to change the size of the frame border.
6708 *
6709 * Deprecated: 2.24: This function will be removed in GTK+ 3
6710 **/
6711 void
gtk_window_set_frame_dimensions(GtkWindow * window,gint left,gint top,gint right,gint bottom)6712 gtk_window_set_frame_dimensions (GtkWindow *window,
6713 gint left,
6714 gint top,
6715 gint right,
6716 gint bottom)
6717 {
6718 GtkWidget *widget;
6719
6720 g_return_if_fail (GTK_IS_WINDOW (window));
6721
6722 widget = GTK_WIDGET (window);
6723
6724 if (window->frame_left == left &&
6725 window->frame_top == top &&
6726 window->frame_right == right &&
6727 window->frame_bottom == bottom)
6728 return;
6729
6730 window->frame_left = left;
6731 window->frame_top = top;
6732 window->frame_right = right;
6733 window->frame_bottom = bottom;
6734
6735 if (gtk_widget_get_realized (widget) && window->frame)
6736 {
6737 gint width = widget->allocation.width + left + right;
6738 gint height = widget->allocation.height + top + bottom;
6739 gdk_window_resize (window->frame, width, height);
6740 gtk_decorated_window_move_resize_window (window,
6741 left, top,
6742 widget->allocation.width,
6743 widget->allocation.height);
6744 }
6745 }
6746
6747 /**
6748 * gtk_window_present:
6749 * @window: a #GtkWindow
6750 *
6751 * Presents a window to the user. This may mean raising the window
6752 * in the stacking order, deiconifying it, moving it to the current
6753 * desktop, and/or giving it the keyboard focus, possibly dependent
6754 * on the user's platform, window manager, and preferences.
6755 *
6756 * If @window is hidden, this function calls gtk_widget_show()
6757 * as well.
6758 *
6759 * This function should be used when the user tries to open a window
6760 * that's already open. Say for example the preferences dialog is
6761 * currently open, and the user chooses Preferences from the menu
6762 * a second time; use gtk_window_present() to move the already-open dialog
6763 * where the user can see it.
6764 *
6765 * If you are calling this function in response to a user interaction,
6766 * it is preferable to use gtk_window_present_with_time().
6767 *
6768 **/
6769 void
gtk_window_present(GtkWindow * window)6770 gtk_window_present (GtkWindow *window)
6771 {
6772 gtk_window_present_with_time (window, GDK_CURRENT_TIME);
6773 }
6774
6775 /**
6776 * gtk_window_present_with_time:
6777 * @window: a #GtkWindow
6778 * @timestamp: the timestamp of the user interaction (typically a
6779 * button or key press event) which triggered this call
6780 *
6781 * Presents a window to the user in response to a user interaction.
6782 * If you need to present a window without a timestamp, use
6783 * gtk_window_present(). See gtk_window_present() for details.
6784 *
6785 * Since: 2.8
6786 **/
6787 void
gtk_window_present_with_time(GtkWindow * window,guint32 timestamp)6788 gtk_window_present_with_time (GtkWindow *window,
6789 guint32 timestamp)
6790 {
6791 GtkWidget *widget;
6792
6793 g_return_if_fail (GTK_IS_WINDOW (window));
6794
6795 widget = GTK_WIDGET (window);
6796
6797 if (gtk_widget_get_visible (widget))
6798 {
6799 g_assert (widget->window != NULL);
6800
6801 gdk_window_show (widget->window);
6802
6803 /* Translate a timestamp of GDK_CURRENT_TIME appropriately */
6804 if (timestamp == GDK_CURRENT_TIME)
6805 {
6806 #ifdef GDK_WINDOWING_X11
6807 GdkDisplay *display;
6808
6809 display = gtk_widget_get_display (GTK_WIDGET (window));
6810 timestamp = gdk_x11_display_get_user_time (display);
6811 #else
6812 timestamp = gtk_get_current_event_time ();
6813 #endif
6814 }
6815
6816 gdk_window_focus (widget->window, timestamp);
6817 }
6818 else
6819 {
6820 gtk_widget_show (widget);
6821 }
6822 }
6823
6824 /**
6825 * gtk_window_iconify:
6826 * @window: a #GtkWindow
6827 *
6828 * Asks to iconify (i.e. minimize) the specified @window. Note that
6829 * you shouldn't assume the window is definitely iconified afterward,
6830 * because other entities (e.g. the user or <link
6831 * linkend="gtk-X11-arch">window manager</link>) could deiconify it
6832 * again, or there may not be a window manager in which case
6833 * iconification isn't possible, etc. But normally the window will end
6834 * up iconified. Just don't write code that crashes if not.
6835 *
6836 * It's permitted to call this function before showing a window,
6837 * in which case the window will be iconified before it ever appears
6838 * onscreen.
6839 *
6840 * You can track iconification via the "window-state-event" signal
6841 * on #GtkWidget.
6842 *
6843 **/
6844 void
gtk_window_iconify(GtkWindow * window)6845 gtk_window_iconify (GtkWindow *window)
6846 {
6847 GtkWidget *widget;
6848 GdkWindow *toplevel;
6849
6850 g_return_if_fail (GTK_IS_WINDOW (window));
6851
6852 widget = GTK_WIDGET (window);
6853
6854 window->iconify_initially = TRUE;
6855
6856 if (window->frame)
6857 toplevel = window->frame;
6858 else
6859 toplevel = widget->window;
6860
6861 if (toplevel != NULL)
6862 gdk_window_iconify (toplevel);
6863 }
6864
6865 /**
6866 * gtk_window_deiconify:
6867 * @window: a #GtkWindow
6868 *
6869 * Asks to deiconify (i.e. unminimize) the specified @window. Note
6870 * that you shouldn't assume the window is definitely deiconified
6871 * afterward, because other entities (e.g. the user or <link
6872 * linkend="gtk-X11-arch">window manager</link>) could iconify it
6873 * again before your code which assumes deiconification gets to run.
6874 *
6875 * You can track iconification via the "window-state-event" signal
6876 * on #GtkWidget.
6877 **/
6878 void
gtk_window_deiconify(GtkWindow * window)6879 gtk_window_deiconify (GtkWindow *window)
6880 {
6881 GtkWidget *widget;
6882 GdkWindow *toplevel;
6883
6884 g_return_if_fail (GTK_IS_WINDOW (window));
6885
6886 widget = GTK_WIDGET (window);
6887
6888 window->iconify_initially = FALSE;
6889
6890 if (window->frame)
6891 toplevel = window->frame;
6892 else
6893 toplevel = widget->window;
6894
6895 if (toplevel != NULL)
6896 gdk_window_deiconify (toplevel);
6897 }
6898
6899 /**
6900 * gtk_window_stick:
6901 * @window: a #GtkWindow
6902 *
6903 * Asks to stick @window, which means that it will appear on all user
6904 * desktops. Note that you shouldn't assume the window is definitely
6905 * stuck afterward, because other entities (e.g. the user or <link
6906 * linkend="gtk-X11-arch">window manager</link>) could unstick it
6907 * again, and some window managers do not support sticking
6908 * windows. But normally the window will end up stuck. Just don't
6909 * write code that crashes if not.
6910 *
6911 * It's permitted to call this function before showing a window.
6912 *
6913 * You can track stickiness via the "window-state-event" signal
6914 * on #GtkWidget.
6915 *
6916 **/
6917 void
gtk_window_stick(GtkWindow * window)6918 gtk_window_stick (GtkWindow *window)
6919 {
6920 GtkWidget *widget;
6921 GdkWindow *toplevel;
6922
6923 g_return_if_fail (GTK_IS_WINDOW (window));
6924
6925 widget = GTK_WIDGET (window);
6926
6927 window->stick_initially = TRUE;
6928
6929 if (window->frame)
6930 toplevel = window->frame;
6931 else
6932 toplevel = widget->window;
6933
6934 if (toplevel != NULL)
6935 gdk_window_stick (toplevel);
6936 }
6937
6938 /**
6939 * gtk_window_unstick:
6940 * @window: a #GtkWindow
6941 *
6942 * Asks to unstick @window, which means that it will appear on only
6943 * one of the user's desktops. Note that you shouldn't assume the
6944 * window is definitely unstuck afterward, because other entities
6945 * (e.g. the user or <link linkend="gtk-X11-arch">window
6946 * manager</link>) could stick it again. But normally the window will
6947 * end up stuck. Just don't write code that crashes if not.
6948 *
6949 * You can track stickiness via the "window-state-event" signal
6950 * on #GtkWidget.
6951 *
6952 **/
6953 void
gtk_window_unstick(GtkWindow * window)6954 gtk_window_unstick (GtkWindow *window)
6955 {
6956 GtkWidget *widget;
6957 GdkWindow *toplevel;
6958
6959 g_return_if_fail (GTK_IS_WINDOW (window));
6960
6961 widget = GTK_WIDGET (window);
6962
6963 window->stick_initially = FALSE;
6964
6965 if (window->frame)
6966 toplevel = window->frame;
6967 else
6968 toplevel = widget->window;
6969
6970 if (toplevel != NULL)
6971 gdk_window_unstick (toplevel);
6972 }
6973
6974 /**
6975 * gtk_window_maximize:
6976 * @window: a #GtkWindow
6977 *
6978 * Asks to maximize @window, so that it becomes full-screen. Note that
6979 * you shouldn't assume the window is definitely maximized afterward,
6980 * because other entities (e.g. the user or <link
6981 * linkend="gtk-X11-arch">window manager</link>) could unmaximize it
6982 * again, and not all window managers support maximization. But
6983 * normally the window will end up maximized. Just don't write code
6984 * that crashes if not.
6985 *
6986 * It's permitted to call this function before showing a window,
6987 * in which case the window will be maximized when it appears onscreen
6988 * initially.
6989 *
6990 * You can track maximization via the "window-state-event" signal
6991 * on #GtkWidget.
6992 *
6993 **/
6994 void
gtk_window_maximize(GtkWindow * window)6995 gtk_window_maximize (GtkWindow *window)
6996 {
6997 GtkWidget *widget;
6998 GdkWindow *toplevel;
6999
7000 g_return_if_fail (GTK_IS_WINDOW (window));
7001
7002 widget = GTK_WIDGET (window);
7003
7004 window->maximize_initially = TRUE;
7005
7006 if (window->frame)
7007 toplevel = window->frame;
7008 else
7009 toplevel = widget->window;
7010
7011 if (toplevel != NULL)
7012 gdk_window_maximize (toplevel);
7013 }
7014
7015 /**
7016 * gtk_window_unmaximize:
7017 * @window: a #GtkWindow
7018 *
7019 * Asks to unmaximize @window. Note that you shouldn't assume the
7020 * window is definitely unmaximized afterward, because other entities
7021 * (e.g. the user or <link linkend="gtk-X11-arch">window
7022 * manager</link>) could maximize it again, and not all window
7023 * managers honor requests to unmaximize. But normally the window will
7024 * end up unmaximized. Just don't write code that crashes if not.
7025 *
7026 * You can track maximization via the "window-state-event" signal
7027 * on #GtkWidget.
7028 *
7029 **/
7030 void
gtk_window_unmaximize(GtkWindow * window)7031 gtk_window_unmaximize (GtkWindow *window)
7032 {
7033 GtkWidget *widget;
7034 GdkWindow *toplevel;
7035
7036 g_return_if_fail (GTK_IS_WINDOW (window));
7037
7038 widget = GTK_WIDGET (window);
7039
7040 window->maximize_initially = FALSE;
7041
7042 if (window->frame)
7043 toplevel = window->frame;
7044 else
7045 toplevel = widget->window;
7046
7047 if (toplevel != NULL)
7048 gdk_window_unmaximize (toplevel);
7049 }
7050
7051 /**
7052 * gtk_window_fullscreen:
7053 * @window: a #GtkWindow
7054 *
7055 * Asks to place @window in the fullscreen state. Note that you
7056 * shouldn't assume the window is definitely full screen afterward,
7057 * because other entities (e.g. the user or <link
7058 * linkend="gtk-X11-arch">window manager</link>) could unfullscreen it
7059 * again, and not all window managers honor requests to fullscreen
7060 * windows. But normally the window will end up fullscreen. Just
7061 * don't write code that crashes if not.
7062 *
7063 * You can track the fullscreen state via the "window-state-event" signal
7064 * on #GtkWidget.
7065 *
7066 * Since: 2.2
7067 **/
7068 void
gtk_window_fullscreen(GtkWindow * window)7069 gtk_window_fullscreen (GtkWindow *window)
7070 {
7071 GtkWidget *widget;
7072 GdkWindow *toplevel;
7073 GtkWindowPrivate *priv;
7074
7075 g_return_if_fail (GTK_IS_WINDOW (window));
7076
7077 widget = GTK_WIDGET (window);
7078 priv = GTK_WINDOW_GET_PRIVATE (window);
7079
7080 priv->fullscreen_initially = TRUE;
7081
7082 if (window->frame)
7083 toplevel = window->frame;
7084 else
7085 toplevel = widget->window;
7086
7087 if (toplevel != NULL)
7088 gdk_window_fullscreen (toplevel);
7089 }
7090
7091 /**
7092 * gtk_window_unfullscreen:
7093 * @window: a #GtkWindow
7094 *
7095 * Asks to toggle off the fullscreen state for @window. Note that you
7096 * shouldn't assume the window is definitely not full screen
7097 * afterward, because other entities (e.g. the user or <link
7098 * linkend="gtk-X11-arch">window manager</link>) could fullscreen it
7099 * again, and not all window managers honor requests to unfullscreen
7100 * windows. But normally the window will end up restored to its normal
7101 * state. Just don't write code that crashes if not.
7102 *
7103 * You can track the fullscreen state via the "window-state-event" signal
7104 * on #GtkWidget.
7105 *
7106 * Since: 2.2
7107 **/
7108 void
gtk_window_unfullscreen(GtkWindow * window)7109 gtk_window_unfullscreen (GtkWindow *window)
7110 {
7111 GtkWidget *widget;
7112 GdkWindow *toplevel;
7113 GtkWindowPrivate *priv;
7114
7115 g_return_if_fail (GTK_IS_WINDOW (window));
7116
7117 widget = GTK_WIDGET (window);
7118 priv = GTK_WINDOW_GET_PRIVATE (window);
7119
7120 priv->fullscreen_initially = FALSE;
7121
7122 if (window->frame)
7123 toplevel = window->frame;
7124 else
7125 toplevel = widget->window;
7126
7127 if (toplevel != NULL)
7128 gdk_window_unfullscreen (toplevel);
7129 }
7130
7131 /**
7132 * gtk_window_set_keep_above:
7133 * @window: a #GtkWindow
7134 * @setting: whether to keep @window above other windows
7135 *
7136 * Asks to keep @window above, so that it stays on top. Note that
7137 * you shouldn't assume the window is definitely above afterward,
7138 * because other entities (e.g. the user or <link
7139 * linkend="gtk-X11-arch">window manager</link>) could not keep it above,
7140 * and not all window managers support keeping windows above. But
7141 * normally the window will end kept above. Just don't write code
7142 * that crashes if not.
7143 *
7144 * It's permitted to call this function before showing a window,
7145 * in which case the window will be kept above when it appears onscreen
7146 * initially.
7147 *
7148 * You can track the above state via the "window-state-event" signal
7149 * on #GtkWidget.
7150 *
7151 * Note that, according to the <ulink
7152 * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
7153 * Manager Hints</ulink> specification, the above state is mainly meant
7154 * for user preferences and should not be used by applications e.g. for
7155 * drawing attention to their dialogs.
7156 *
7157 * Since: 2.4
7158 **/
7159 void
gtk_window_set_keep_above(GtkWindow * window,gboolean setting)7160 gtk_window_set_keep_above (GtkWindow *window,
7161 gboolean setting)
7162 {
7163 GtkWidget *widget;
7164 GtkWindowPrivate *priv;
7165 GdkWindow *toplevel;
7166
7167 g_return_if_fail (GTK_IS_WINDOW (window));
7168
7169 widget = GTK_WIDGET (window);
7170 priv = GTK_WINDOW_GET_PRIVATE (window);
7171
7172 priv->above_initially = setting != FALSE;
7173 if (setting)
7174 priv->below_initially = FALSE;
7175
7176 if (window->frame)
7177 toplevel = window->frame;
7178 else
7179 toplevel = widget->window;
7180
7181 if (toplevel != NULL)
7182 gdk_window_set_keep_above (toplevel, setting);
7183 }
7184
7185 /**
7186 * gtk_window_set_keep_below:
7187 * @window: a #GtkWindow
7188 * @setting: whether to keep @window below other windows
7189 *
7190 * Asks to keep @window below, so that it stays in bottom. Note that
7191 * you shouldn't assume the window is definitely below afterward,
7192 * because other entities (e.g. the user or <link
7193 * linkend="gtk-X11-arch">window manager</link>) could not keep it below,
7194 * and not all window managers support putting windows below. But
7195 * normally the window will be kept below. Just don't write code
7196 * that crashes if not.
7197 *
7198 * It's permitted to call this function before showing a window,
7199 * in which case the window will be kept below when it appears onscreen
7200 * initially.
7201 *
7202 * You can track the below state via the "window-state-event" signal
7203 * on #GtkWidget.
7204 *
7205 * Note that, according to the <ulink
7206 * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
7207 * Manager Hints</ulink> specification, the above state is mainly meant
7208 * for user preferences and should not be used by applications e.g. for
7209 * drawing attention to their dialogs.
7210 *
7211 * Since: 2.4
7212 **/
7213 void
gtk_window_set_keep_below(GtkWindow * window,gboolean setting)7214 gtk_window_set_keep_below (GtkWindow *window,
7215 gboolean setting)
7216 {
7217 GtkWidget *widget;
7218 GtkWindowPrivate *priv;
7219 GdkWindow *toplevel;
7220
7221 g_return_if_fail (GTK_IS_WINDOW (window));
7222
7223 widget = GTK_WIDGET (window);
7224 priv = GTK_WINDOW_GET_PRIVATE (window);
7225
7226 priv->below_initially = setting != FALSE;
7227 if (setting)
7228 priv->above_initially = FALSE;
7229
7230 if (window->frame)
7231 toplevel = window->frame;
7232 else
7233 toplevel = widget->window;
7234
7235 if (toplevel != NULL)
7236 gdk_window_set_keep_below (toplevel, setting);
7237 }
7238
7239 /**
7240 * gtk_window_set_resizable:
7241 * @window: a #GtkWindow
7242 * @resizable: %TRUE if the user can resize this window
7243 *
7244 * Sets whether the user can resize a window. Windows are user resizable
7245 * by default.
7246 **/
7247 void
gtk_window_set_resizable(GtkWindow * window,gboolean resizable)7248 gtk_window_set_resizable (GtkWindow *window,
7249 gboolean resizable)
7250 {
7251 g_return_if_fail (GTK_IS_WINDOW (window));
7252
7253 gtk_window_set_policy_internal (window, FALSE, resizable, FALSE);
7254 }
7255
7256 /**
7257 * gtk_window_get_resizable:
7258 * @window: a #GtkWindow
7259 *
7260 * Gets the value set by gtk_window_set_resizable().
7261 *
7262 * Return value: %TRUE if the user can resize the window
7263 **/
7264 gboolean
gtk_window_get_resizable(GtkWindow * window)7265 gtk_window_get_resizable (GtkWindow *window)
7266 {
7267 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
7268
7269 /* allow_grow is most likely to indicate the semantic concept we
7270 * mean by "resizable" (and will be a reliable indicator if
7271 * set_policy() hasn't been called)
7272 */
7273 return window->allow_grow;
7274 }
7275
7276 /**
7277 * gtk_window_set_gravity:
7278 * @window: a #GtkWindow
7279 * @gravity: window gravity
7280 *
7281 * Window gravity defines the meaning of coordinates passed to
7282 * gtk_window_move(). See gtk_window_move() and #GdkGravity for
7283 * more details.
7284 *
7285 * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
7286 * typically "do what you mean."
7287 *
7288 **/
7289 void
gtk_window_set_gravity(GtkWindow * window,GdkGravity gravity)7290 gtk_window_set_gravity (GtkWindow *window,
7291 GdkGravity gravity)
7292 {
7293 g_return_if_fail (GTK_IS_WINDOW (window));
7294
7295 if (gravity != window->gravity)
7296 {
7297 window->gravity = gravity;
7298
7299 /* gtk_window_move_resize() will adapt gravity
7300 */
7301 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
7302
7303 g_object_notify (G_OBJECT (window), "gravity");
7304 }
7305 }
7306
7307 /**
7308 * gtk_window_get_gravity:
7309 * @window: a #GtkWindow
7310 *
7311 * Gets the value set by gtk_window_set_gravity().
7312 *
7313 * Return value: (transfer none): window gravity
7314 **/
7315 GdkGravity
gtk_window_get_gravity(GtkWindow * window)7316 gtk_window_get_gravity (GtkWindow *window)
7317 {
7318 g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
7319
7320 return window->gravity;
7321 }
7322
7323 /**
7324 * gtk_window_begin_resize_drag:
7325 * @window: a #GtkWindow
7326 * @button: mouse button that initiated the drag
7327 * @edge: position of the resize control
7328 * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
7329 * @root_y: Y position where the user clicked to initiate the drag
7330 * @timestamp: timestamp from the click event that initiated the drag
7331 *
7332 * Starts resizing a window. This function is used if an application
7333 * has window resizing controls. When GDK can support it, the resize
7334 * will be done using the standard mechanism for the <link
7335 * linkend="gtk-X11-arch">window manager</link> or windowing
7336 * system. Otherwise, GDK will try to emulate window resizing,
7337 * potentially not all that well, depending on the windowing system.
7338 *
7339 **/
7340 void
gtk_window_begin_resize_drag(GtkWindow * window,GdkWindowEdge edge,gint button,gint root_x,gint root_y,guint32 timestamp)7341 gtk_window_begin_resize_drag (GtkWindow *window,
7342 GdkWindowEdge edge,
7343 gint button,
7344 gint root_x,
7345 gint root_y,
7346 guint32 timestamp)
7347 {
7348 GtkWidget *widget;
7349 GdkWindow *toplevel;
7350
7351 g_return_if_fail (GTK_IS_WINDOW (window));
7352 widget = GTK_WIDGET (window);
7353 g_return_if_fail (gtk_widget_get_visible (widget));
7354
7355 if (window->frame)
7356 toplevel = window->frame;
7357 else
7358 toplevel = widget->window;
7359
7360 gdk_window_begin_resize_drag (toplevel,
7361 edge, button,
7362 root_x, root_y,
7363 timestamp);
7364 }
7365
7366 /**
7367 * gtk_window_get_frame_dimensions:
7368 * @window: a #GtkWindow
7369 * @left: (out) (allow-none): location to store the width of the frame at the left, or %NULL
7370 * @top: (out) (allow-none): location to store the height of the frame at the top, or %NULL
7371 * @right: (out) (allow-none): location to store the width of the frame at the returns, or %NULL
7372 * @bottom: (out) (allow-none): location to store the height of the frame at the bottom, or %NULL
7373 *
7374 * (Note: this is a special-purpose function intended for the
7375 * framebuffer port; see gtk_window_set_has_frame(). It will not
7376 * return the size of the window border drawn by the <link
7377 * linkend="gtk-X11-arch">window manager</link>, which is the normal
7378 * case when using a windowing system. See
7379 * gdk_window_get_frame_extents() to get the standard window border
7380 * extents.)
7381 *
7382 * Retrieves the dimensions of the frame window for this toplevel.
7383 * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions().
7384 *
7385 * Deprecated: 2.24: This function will be removed in GTK+ 3
7386 **/
7387 void
gtk_window_get_frame_dimensions(GtkWindow * window,gint * left,gint * top,gint * right,gint * bottom)7388 gtk_window_get_frame_dimensions (GtkWindow *window,
7389 gint *left,
7390 gint *top,
7391 gint *right,
7392 gint *bottom)
7393 {
7394 g_return_if_fail (GTK_IS_WINDOW (window));
7395
7396 if (left)
7397 *left = window->frame_left;
7398 if (top)
7399 *top = window->frame_top;
7400 if (right)
7401 *right = window->frame_right;
7402 if (bottom)
7403 *bottom = window->frame_bottom;
7404 }
7405
7406 /**
7407 * gtk_window_begin_move_drag:
7408 * @window: a #GtkWindow
7409 * @button: mouse button that initiated the drag
7410 * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
7411 * @root_y: Y position where the user clicked to initiate the drag
7412 * @timestamp: timestamp from the click event that initiated the drag
7413 *
7414 * Starts moving a window. This function is used if an application has
7415 * window movement grips. When GDK can support it, the window movement
7416 * will be done using the standard mechanism for the <link
7417 * linkend="gtk-X11-arch">window manager</link> or windowing
7418 * system. Otherwise, GDK will try to emulate window movement,
7419 * potentially not all that well, depending on the windowing system.
7420 *
7421 **/
7422 void
gtk_window_begin_move_drag(GtkWindow * window,gint button,gint root_x,gint root_y,guint32 timestamp)7423 gtk_window_begin_move_drag (GtkWindow *window,
7424 gint button,
7425 gint root_x,
7426 gint root_y,
7427 guint32 timestamp)
7428 {
7429 GtkWidget *widget;
7430 GdkWindow *toplevel;
7431
7432 g_return_if_fail (GTK_IS_WINDOW (window));
7433 widget = GTK_WIDGET (window);
7434 g_return_if_fail (gtk_widget_get_visible (widget));
7435
7436 if (window->frame)
7437 toplevel = window->frame;
7438 else
7439 toplevel = widget->window;
7440
7441 gdk_window_begin_move_drag (toplevel,
7442 button,
7443 root_x, root_y,
7444 timestamp);
7445 }
7446
7447 /**
7448 * gtk_window_set_screen:
7449 * @window: a #GtkWindow.
7450 * @screen: a #GdkScreen.
7451 *
7452 * Sets the #GdkScreen where the @window is displayed; if
7453 * the window is already mapped, it will be unmapped, and
7454 * then remapped on the new screen.
7455 *
7456 * Since: 2.2
7457 */
7458 void
gtk_window_set_screen(GtkWindow * window,GdkScreen * screen)7459 gtk_window_set_screen (GtkWindow *window,
7460 GdkScreen *screen)
7461 {
7462 GtkWidget *widget;
7463 GdkScreen *previous_screen;
7464 gboolean was_mapped;
7465
7466 g_return_if_fail (GTK_IS_WINDOW (window));
7467 g_return_if_fail (GDK_IS_SCREEN (screen));
7468
7469 if (screen == window->screen)
7470 return;
7471
7472 widget = GTK_WIDGET (window);
7473
7474 previous_screen = window->screen;
7475 was_mapped = gtk_widget_get_mapped (widget);
7476
7477 if (was_mapped)
7478 gtk_widget_unmap (widget);
7479 if (gtk_widget_get_realized (widget))
7480 gtk_widget_unrealize (widget);
7481
7482 gtk_window_free_key_hash (window);
7483 window->screen = screen;
7484 gtk_widget_reset_rc_styles (widget);
7485 if (screen != previous_screen)
7486 {
7487 g_signal_handlers_disconnect_by_func (previous_screen,
7488 gtk_window_on_composited_changed, window);
7489 g_signal_connect (screen, "composited-changed",
7490 G_CALLBACK (gtk_window_on_composited_changed), window);
7491
7492 _gtk_widget_propagate_screen_changed (widget, previous_screen);
7493 _gtk_widget_propagate_composited_changed (widget);
7494 }
7495 g_object_notify (G_OBJECT (window), "screen");
7496
7497 if (was_mapped)
7498 gtk_widget_map (widget);
7499 }
7500
7501 static void
gtk_window_on_composited_changed(GdkScreen * screen,GtkWindow * window)7502 gtk_window_on_composited_changed (GdkScreen *screen,
7503 GtkWindow *window)
7504 {
7505 gtk_widget_queue_draw (GTK_WIDGET (window));
7506
7507 _gtk_widget_propagate_composited_changed (GTK_WIDGET (window));
7508 }
7509
7510 static GdkScreen *
gtk_window_check_screen(GtkWindow * window)7511 gtk_window_check_screen (GtkWindow *window)
7512 {
7513 if (window->screen)
7514 return window->screen;
7515 else
7516 {
7517 g_warning ("Screen for GtkWindow not set; you must always set\n"
7518 "a screen for a GtkWindow before using the window");
7519 return NULL;
7520 }
7521 }
7522
7523 /**
7524 * gtk_window_get_screen:
7525 * @window: a #GtkWindow.
7526 *
7527 * Returns the #GdkScreen associated with @window.
7528 *
7529 * Return value: (transfer none): a #GdkScreen.
7530 *
7531 * Since: 2.2
7532 */
7533 GdkScreen*
gtk_window_get_screen(GtkWindow * window)7534 gtk_window_get_screen (GtkWindow *window)
7535 {
7536 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
7537
7538 return window->screen;
7539 }
7540
7541 /**
7542 * gtk_window_is_active:
7543 * @window: a #GtkWindow
7544 *
7545 * Returns whether the window is part of the current active toplevel.
7546 * (That is, the toplevel window receiving keystrokes.)
7547 * The return value is %TRUE if the window is active toplevel
7548 * itself, but also if it is, say, a #GtkPlug embedded in the active toplevel.
7549 * You might use this function if you wanted to draw a widget
7550 * differently in an active window from a widget in an inactive window.
7551 * See gtk_window_has_toplevel_focus()
7552 *
7553 * Return value: %TRUE if the window part of the current active window.
7554 *
7555 * Since: 2.4
7556 **/
7557 gboolean
gtk_window_is_active(GtkWindow * window)7558 gtk_window_is_active (GtkWindow *window)
7559 {
7560 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
7561
7562 return window->is_active;
7563 }
7564
7565 /**
7566 * gtk_window_has_toplevel_focus:
7567 * @window: a #GtkWindow
7568 *
7569 * Returns whether the input focus is within this GtkWindow.
7570 * For real toplevel windows, this is identical to gtk_window_is_active(),
7571 * but for embedded windows, like #GtkPlug, the results will differ.
7572 *
7573 * Return value: %TRUE if the input focus is within this GtkWindow
7574 *
7575 * Since: 2.4
7576 **/
7577 gboolean
gtk_window_has_toplevel_focus(GtkWindow * window)7578 gtk_window_has_toplevel_focus (GtkWindow *window)
7579 {
7580 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
7581
7582 return window->has_toplevel_focus;
7583 }
7584
7585 static void
gtk_window_group_class_init(GtkWindowGroupClass * klass)7586 gtk_window_group_class_init (GtkWindowGroupClass *klass)
7587 {
7588 }
7589
7590 GType
gtk_window_group_get_type(void)7591 gtk_window_group_get_type (void)
7592 {
7593 static GType window_group_type = 0;
7594
7595 if (!window_group_type)
7596 {
7597 const GTypeInfo window_group_info =
7598 {
7599 sizeof (GtkWindowGroupClass),
7600 NULL, /* base_init */
7601 NULL, /* base_finalize */
7602 (GClassInitFunc) gtk_window_group_class_init,
7603 NULL, /* class_finalize */
7604 NULL, /* class_data */
7605 sizeof (GtkWindowGroup),
7606 0, /* n_preallocs */
7607 (GInstanceInitFunc) NULL,
7608 };
7609
7610 window_group_type = g_type_register_static (G_TYPE_OBJECT, I_("GtkWindowGroup"),
7611 &window_group_info, 0);
7612 }
7613
7614 return window_group_type;
7615 }
7616
7617 /**
7618 * gtk_window_group_new:
7619 *
7620 * Creates a new #GtkWindowGroup object. Grabs added with
7621 * gtk_grab_add() only affect windows within the same #GtkWindowGroup.
7622 *
7623 * Return value: a new #GtkWindowGroup.
7624 **/
7625 GtkWindowGroup *
gtk_window_group_new(void)7626 gtk_window_group_new (void)
7627 {
7628 return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
7629 }
7630
7631 static void
window_group_cleanup_grabs(GtkWindowGroup * group,GtkWindow * window)7632 window_group_cleanup_grabs (GtkWindowGroup *group,
7633 GtkWindow *window)
7634 {
7635 GSList *tmp_list;
7636 GSList *to_remove = NULL;
7637
7638 tmp_list = group->grabs;
7639 while (tmp_list)
7640 {
7641 if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
7642 to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
7643 tmp_list = tmp_list->next;
7644 }
7645
7646 while (to_remove)
7647 {
7648 gtk_grab_remove (to_remove->data);
7649 g_object_unref (to_remove->data);
7650 to_remove = g_slist_delete_link (to_remove, to_remove);
7651 }
7652 }
7653
7654 /**
7655 * gtk_window_group_add_window:
7656 * @window_group: a #GtkWindowGroup
7657 * @window: the #GtkWindow to add
7658 *
7659 * Adds a window to a #GtkWindowGroup.
7660 **/
7661 void
gtk_window_group_add_window(GtkWindowGroup * window_group,GtkWindow * window)7662 gtk_window_group_add_window (GtkWindowGroup *window_group,
7663 GtkWindow *window)
7664 {
7665 g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
7666 g_return_if_fail (GTK_IS_WINDOW (window));
7667
7668 if (window->group != window_group)
7669 {
7670 g_object_ref (window);
7671 g_object_ref (window_group);
7672
7673 if (window->group)
7674 gtk_window_group_remove_window (window->group, window);
7675 else
7676 window_group_cleanup_grabs (gtk_window_get_group (NULL), window);
7677
7678 window->group = window_group;
7679
7680 g_object_unref (window);
7681 }
7682 }
7683
7684 /**
7685 * gtk_window_group_remove_window:
7686 * @window_group: a #GtkWindowGroup
7687 * @window: the #GtkWindow to remove
7688 *
7689 * Removes a window from a #GtkWindowGroup.
7690 **/
7691 void
gtk_window_group_remove_window(GtkWindowGroup * window_group,GtkWindow * window)7692 gtk_window_group_remove_window (GtkWindowGroup *window_group,
7693 GtkWindow *window)
7694 {
7695 g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
7696 g_return_if_fail (GTK_IS_WINDOW (window));
7697 g_return_if_fail (window->group == window_group);
7698
7699 g_object_ref (window);
7700
7701 window_group_cleanup_grabs (window_group, window);
7702 window->group = NULL;
7703
7704 g_object_unref (window_group);
7705 g_object_unref (window);
7706 }
7707
7708 /**
7709 * gtk_window_group_list_windows:
7710 * @window_group: a #GtkWindowGroup
7711 *
7712 * Returns a list of the #GtkWindows that belong to @window_group.
7713 *
7714 * Returns: (element-type GtkWidget) (transfer container): A newly-allocated list of
7715 * windows inside the group.
7716 *
7717 * Since: 2.14
7718 **/
7719 GList *
gtk_window_group_list_windows(GtkWindowGroup * window_group)7720 gtk_window_group_list_windows (GtkWindowGroup *window_group)
7721 {
7722 GList *toplevels, *toplevel, *group_windows;
7723
7724 g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
7725
7726 group_windows = NULL;
7727 toplevels = gtk_window_list_toplevels ();
7728
7729 for (toplevel = toplevels; toplevel; toplevel = toplevel->next)
7730 {
7731 GtkWindow *window = toplevel->data;
7732
7733 if (window_group == window->group)
7734 group_windows = g_list_prepend (group_windows, window);
7735 }
7736
7737 return g_list_reverse (group_windows);
7738 }
7739
7740 /**
7741 * gtk_window_get_group:
7742 * @window: (allow-none): a #GtkWindow, or %NULL
7743 *
7744 * Returns the group for @window or the default group, if
7745 * @window is %NULL or if @window does not have an explicit
7746 * window group.
7747 *
7748 * Returns: (transfer none): the #GtkWindowGroup for a window or the default group
7749 *
7750 * Since: 2.10
7751 */
7752 GtkWindowGroup *
gtk_window_get_group(GtkWindow * window)7753 gtk_window_get_group (GtkWindow *window)
7754 {
7755 if (window && window->group)
7756 return window->group;
7757 else
7758 {
7759 static GtkWindowGroup *default_group = NULL;
7760
7761 if (!default_group)
7762 default_group = gtk_window_group_new ();
7763
7764 return default_group;
7765 }
7766 }
7767
7768 /**
7769 * gtk_window_has_group:
7770 * @window: a #GtkWindow
7771 *
7772 * Returns whether @window has an explicit window group.
7773 *
7774 * Return value: %TRUE if @window has an explicit window group.
7775 *
7776 * Since 2.22
7777 **/
7778 gboolean
gtk_window_has_group(GtkWindow * window)7779 gtk_window_has_group (GtkWindow *window)
7780 {
7781 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
7782
7783 return window->group != NULL;
7784 }
7785
7786 /**
7787 * gtk_window_group_get_current_current_grab:
7788 * @window_group: a #GtkWindowGroup
7789 *
7790 * Gets the current grab widget of the given group,
7791 * see gtk_grab_add().
7792 *
7793 * Returns: (transfer none): the current grab widget of the group
7794 *
7795 * Since: 2.22
7796 */
7797 GtkWidget *
gtk_window_group_get_current_grab(GtkWindowGroup * window_group)7798 gtk_window_group_get_current_grab (GtkWindowGroup *window_group)
7799 {
7800 if (window_group->grabs)
7801 return GTK_WIDGET (window_group->grabs->data);
7802 return NULL;
7803 }
7804
7805 /*
7806 Derived from XParseGeometry() in XFree86
7807
7808 Copyright 1985, 1986, 1987,1998 The Open Group
7809
7810 All Rights Reserved.
7811
7812 The above copyright notice and this permission notice shall be included
7813 in all copies or substantial portions of the Software.
7814
7815 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
7816 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
7817 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
7818 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
7819 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
7820 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
7821 OTHER DEALINGS IN THE SOFTWARE.
7822
7823 Except as contained in this notice, the name of The Open Group shall
7824 not be used in advertising or otherwise to promote the sale, use or
7825 other dealings in this Software without prior written authorization
7826 from The Open Group.
7827 */
7828
7829
7830 /*
7831 * XParseGeometry parses strings of the form
7832 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
7833 * width, height, xoffset, and yoffset are unsigned integers.
7834 * Example: "=80x24+300-49"
7835 * The equal sign is optional.
7836 * It returns a bitmask that indicates which of the four values
7837 * were actually found in the string. For each value found,
7838 * the corresponding argument is updated; for each value
7839 * not found, the corresponding argument is left unchanged.
7840 */
7841
7842 /* The following code is from Xlib, and is minimally modified, so we
7843 * can track any upstream changes if required. Don't change this
7844 * code. Or if you do, put in a huge comment marking which thing
7845 * changed.
7846 */
7847
7848 static int
read_int(gchar * string,gchar ** next)7849 read_int (gchar *string,
7850 gchar **next)
7851 {
7852 int result = 0;
7853 int sign = 1;
7854
7855 if (*string == '+')
7856 string++;
7857 else if (*string == '-')
7858 {
7859 string++;
7860 sign = -1;
7861 }
7862
7863 for (; (*string >= '0') && (*string <= '9'); string++)
7864 {
7865 result = (result * 10) + (*string - '0');
7866 }
7867
7868 *next = string;
7869
7870 if (sign >= 0)
7871 return (result);
7872 else
7873 return (-result);
7874 }
7875
7876 /*
7877 * Bitmask returned by XParseGeometry(). Each bit tells if the corresponding
7878 * value (x, y, width, height) was found in the parsed string.
7879 */
7880 #define NoValue 0x0000
7881 #define XValue 0x0001
7882 #define YValue 0x0002
7883 #define WidthValue 0x0004
7884 #define HeightValue 0x0008
7885 #define AllValues 0x000F
7886 #define XNegative 0x0010
7887 #define YNegative 0x0020
7888
7889 /* Try not to reformat/modify, so we can compare/sync with X sources */
7890 static int
gtk_XParseGeometry(const char * string,int * x,int * y,unsigned int * width,unsigned int * height)7891 gtk_XParseGeometry (const char *string,
7892 int *x,
7893 int *y,
7894 unsigned int *width,
7895 unsigned int *height)
7896 {
7897 int mask = NoValue;
7898 char *strind;
7899 unsigned int tempWidth, tempHeight;
7900 int tempX, tempY;
7901 char *nextCharacter;
7902
7903 /* These initializations are just to silence gcc */
7904 tempWidth = 0;
7905 tempHeight = 0;
7906 tempX = 0;
7907 tempY = 0;
7908
7909 if ( (string == NULL) || (*string == '\0')) return(mask);
7910 if (*string == '=')
7911 string++; /* ignore possible '=' at beg of geometry spec */
7912
7913 strind = (char *)string;
7914 if (*strind != '+' && *strind != '-' && *strind != 'x') {
7915 tempWidth = read_int(strind, &nextCharacter);
7916 if (strind == nextCharacter)
7917 return (0);
7918 strind = nextCharacter;
7919 mask |= WidthValue;
7920 }
7921
7922 if (*strind == 'x' || *strind == 'X') {
7923 strind++;
7924 tempHeight = read_int(strind, &nextCharacter);
7925 if (strind == nextCharacter)
7926 return (0);
7927 strind = nextCharacter;
7928 mask |= HeightValue;
7929 }
7930
7931 if ((*strind == '+') || (*strind == '-')) {
7932 if (*strind == '-') {
7933 strind++;
7934 tempX = -read_int(strind, &nextCharacter);
7935 if (strind == nextCharacter)
7936 return (0);
7937 strind = nextCharacter;
7938 mask |= XNegative;
7939
7940 }
7941 else
7942 { strind++;
7943 tempX = read_int(strind, &nextCharacter);
7944 if (strind == nextCharacter)
7945 return(0);
7946 strind = nextCharacter;
7947 }
7948 mask |= XValue;
7949 if ((*strind == '+') || (*strind == '-')) {
7950 if (*strind == '-') {
7951 strind++;
7952 tempY = -read_int(strind, &nextCharacter);
7953 if (strind == nextCharacter)
7954 return(0);
7955 strind = nextCharacter;
7956 mask |= YNegative;
7957
7958 }
7959 else
7960 {
7961 strind++;
7962 tempY = read_int(strind, &nextCharacter);
7963 if (strind == nextCharacter)
7964 return(0);
7965 strind = nextCharacter;
7966 }
7967 mask |= YValue;
7968 }
7969 }
7970
7971 /* If strind isn't at the end of the string the it's an invalid
7972 geometry specification. */
7973
7974 if (*strind != '\0') return (0);
7975
7976 if (mask & XValue)
7977 *x = tempX;
7978 if (mask & YValue)
7979 *y = tempY;
7980 if (mask & WidthValue)
7981 *width = tempWidth;
7982 if (mask & HeightValue)
7983 *height = tempHeight;
7984 return (mask);
7985 }
7986
7987 /**
7988 * gtk_window_parse_geometry:
7989 * @window: a #GtkWindow
7990 * @geometry: geometry string
7991 *
7992 * Parses a standard X Window System geometry string - see the
7993 * manual page for X (type 'man X') for details on this.
7994 * gtk_window_parse_geometry() does work on all GTK+ ports
7995 * including Win32 but is primarily intended for an X environment.
7996 *
7997 * If either a size or a position can be extracted from the
7998 * geometry string, gtk_window_parse_geometry() returns %TRUE
7999 * and calls gtk_window_set_default_size() and/or gtk_window_move()
8000 * to resize/move the window.
8001 *
8002 * If gtk_window_parse_geometry() returns %TRUE, it will also
8003 * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
8004 * indicating to the window manager that the size/position of
8005 * the window was user-specified. This causes most window
8006 * managers to honor the geometry.
8007 *
8008 * Note that for gtk_window_parse_geometry() to work as expected, it has
8009 * to be called when the window has its "final" size, i.e. after calling
8010 * gtk_widget_show_all() on the contents and gtk_window_set_geometry_hints()
8011 * on the window.
8012 * |[
8013 * #include <gtk/gtk.h>
8014 *
8015 * static void
8016 * fill_with_content (GtkWidget *vbox)
8017 * {
8018 * /* fill with content... */
8019 * }
8020 *
8021 * int
8022 * main (int argc, char *argv[])
8023 * {
8024 * GtkWidget *window, *vbox;
8025 * GdkGeometry size_hints = {
8026 * 100, 50, 0, 0, 100, 50, 10, 10, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
8027 * };
8028 *
8029 * gtk_init (&argc, &argv);
8030 *
8031 * window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8032 * vbox = gtk_vbox_new (FALSE, 0);
8033 *
8034 * gtk_container_add (GTK_CONTAINER (window), vbox);
8035 * fill_with_content (vbox);
8036 * gtk_widget_show_all (vbox);
8037 *
8038 * gtk_window_set_geometry_hints (GTK_WINDOW (window),
8039 * window,
8040 * &size_hints,
8041 * GDK_HINT_MIN_SIZE |
8042 * GDK_HINT_BASE_SIZE |
8043 * GDK_HINT_RESIZE_INC);
8044 *
8045 * if (argc > 1)
8046 * {
8047 * if (!gtk_window_parse_geometry (GTK_WINDOW (window), argv[1]))
8048 * fprintf (stderr, "Failed to parse '%s'\n", argv[1]);
8049 * }
8050 *
8051 * gtk_widget_show_all (window);
8052 * gtk_main ();
8053 *
8054 * return 0;
8055 * }
8056 * ]|
8057 *
8058 * Return value: %TRUE if string was parsed successfully
8059 **/
8060 gboolean
gtk_window_parse_geometry(GtkWindow * window,const gchar * geometry)8061 gtk_window_parse_geometry (GtkWindow *window,
8062 const gchar *geometry)
8063 {
8064 gint result, x = 0, y = 0;
8065 guint w, h;
8066 GdkGravity grav;
8067 gboolean size_set, pos_set;
8068 GdkScreen *screen;
8069
8070 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8071 g_return_val_if_fail (geometry != NULL, FALSE);
8072
8073 screen = gtk_window_check_screen (window);
8074
8075 result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
8076
8077 size_set = FALSE;
8078 if ((result & WidthValue) || (result & HeightValue))
8079 {
8080 gtk_window_set_default_size_internal (window,
8081 TRUE, result & WidthValue ? w : -1,
8082 TRUE, result & HeightValue ? h : -1,
8083 TRUE);
8084 size_set = TRUE;
8085 }
8086
8087 gtk_window_get_size (window, (gint *)&w, (gint *)&h);
8088
8089 grav = GDK_GRAVITY_NORTH_WEST;
8090
8091 if ((result & XNegative) && (result & YNegative))
8092 grav = GDK_GRAVITY_SOUTH_EAST;
8093 else if (result & XNegative)
8094 grav = GDK_GRAVITY_NORTH_EAST;
8095 else if (result & YNegative)
8096 grav = GDK_GRAVITY_SOUTH_WEST;
8097
8098 if ((result & XValue) == 0)
8099 x = 0;
8100
8101 if ((result & YValue) == 0)
8102 y = 0;
8103
8104 if (grav == GDK_GRAVITY_SOUTH_WEST ||
8105 grav == GDK_GRAVITY_SOUTH_EAST)
8106 y = gdk_screen_get_height (screen) - h + y;
8107
8108 if (grav == GDK_GRAVITY_SOUTH_EAST ||
8109 grav == GDK_GRAVITY_NORTH_EAST)
8110 x = gdk_screen_get_width (screen) - w + x;
8111
8112 /* we don't let you put a window offscreen; maybe some people would
8113 * prefer to be able to, but it's kind of a bogus thing to do.
8114 */
8115 if (y < 0)
8116 y = 0;
8117
8118 if (x < 0)
8119 x = 0;
8120
8121 pos_set = FALSE;
8122 if ((result & XValue) || (result & YValue))
8123 {
8124 gtk_window_set_gravity (window, grav);
8125 gtk_window_move (window, x, y);
8126 pos_set = TRUE;
8127 }
8128
8129 if (size_set || pos_set)
8130 {
8131 /* Set USSize, USPosition hints */
8132 GtkWindowGeometryInfo *info;
8133
8134 info = gtk_window_get_geometry_info (window, TRUE);
8135
8136 if (pos_set)
8137 info->mask |= GDK_HINT_USER_POS;
8138 if (size_set)
8139 info->mask |= GDK_HINT_USER_SIZE;
8140 }
8141
8142 return result != 0;
8143 }
8144
8145 static void
gtk_window_mnemonic_hash_foreach(guint keyval,GSList * targets,gpointer data)8146 gtk_window_mnemonic_hash_foreach (guint keyval,
8147 GSList *targets,
8148 gpointer data)
8149 {
8150 struct {
8151 GtkWindow *window;
8152 GtkWindowKeysForeachFunc func;
8153 gpointer func_data;
8154 } *info = data;
8155
8156 (*info->func) (info->window, keyval, info->window->mnemonic_modifier, TRUE, info->func_data);
8157 }
8158
8159 void
_gtk_window_keys_foreach(GtkWindow * window,GtkWindowKeysForeachFunc func,gpointer func_data)8160 _gtk_window_keys_foreach (GtkWindow *window,
8161 GtkWindowKeysForeachFunc func,
8162 gpointer func_data)
8163 {
8164 GSList *groups;
8165 GtkMnemonicHash *mnemonic_hash;
8166
8167 struct {
8168 GtkWindow *window;
8169 GtkWindowKeysForeachFunc func;
8170 gpointer func_data;
8171 } info;
8172
8173 info.window = window;
8174 info.func = func;
8175 info.func_data = func_data;
8176
8177 mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
8178 if (mnemonic_hash)
8179 _gtk_mnemonic_hash_foreach (mnemonic_hash,
8180 gtk_window_mnemonic_hash_foreach, &info);
8181
8182 groups = gtk_accel_groups_from_object (G_OBJECT (window));
8183 while (groups)
8184 {
8185 GtkAccelGroup *group = groups->data;
8186 gint i;
8187
8188 for (i = 0; i < group->n_accels; i++)
8189 {
8190 GtkAccelKey *key = &group->priv_accels[i].key;
8191
8192 if (key->accel_key)
8193 (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
8194 }
8195
8196 groups = groups->next;
8197 }
8198 }
8199
8200 static void
gtk_window_keys_changed(GtkWindow * window)8201 gtk_window_keys_changed (GtkWindow *window)
8202 {
8203 gtk_window_free_key_hash (window);
8204 gtk_window_get_key_hash (window);
8205 }
8206
8207 typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
8208
8209 struct _GtkWindowKeyEntry
8210 {
8211 guint keyval;
8212 guint modifiers;
8213 guint is_mnemonic : 1;
8214 };
8215
8216 static void
window_key_entry_destroy(gpointer data)8217 window_key_entry_destroy (gpointer data)
8218 {
8219 g_slice_free (GtkWindowKeyEntry, data);
8220 }
8221
8222 static void
add_to_key_hash(GtkWindow * window,guint keyval,GdkModifierType modifiers,gboolean is_mnemonic,gpointer data)8223 add_to_key_hash (GtkWindow *window,
8224 guint keyval,
8225 GdkModifierType modifiers,
8226 gboolean is_mnemonic,
8227 gpointer data)
8228 {
8229 GtkKeyHash *key_hash = data;
8230
8231 GtkWindowKeyEntry *entry = g_slice_new (GtkWindowKeyEntry);
8232
8233 entry->keyval = keyval;
8234 entry->modifiers = modifiers;
8235 entry->is_mnemonic = is_mnemonic;
8236
8237 /* GtkAccelGroup stores lowercased accelerators. To deal
8238 * with this, if <Shift> was specified, uppercase.
8239 */
8240 if (modifiers & GDK_SHIFT_MASK)
8241 {
8242 if (keyval == GDK_Tab)
8243 keyval = GDK_ISO_Left_Tab;
8244 else
8245 keyval = gdk_keyval_to_upper (keyval);
8246 }
8247
8248 _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
8249 }
8250
8251 static GtkKeyHash *
gtk_window_get_key_hash(GtkWindow * window)8252 gtk_window_get_key_hash (GtkWindow *window)
8253 {
8254 GdkScreen *screen = gtk_window_check_screen (window);
8255 GtkKeyHash *key_hash = g_object_get_qdata (G_OBJECT (window), quark_gtk_window_key_hash);
8256
8257 if (key_hash)
8258 return key_hash;
8259
8260 key_hash = _gtk_key_hash_new (gdk_keymap_get_for_display (gdk_screen_get_display (screen)),
8261 (GDestroyNotify)window_key_entry_destroy);
8262 _gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
8263 g_object_set_qdata (G_OBJECT (window), quark_gtk_window_key_hash, key_hash);
8264
8265 return key_hash;
8266 }
8267
8268 static void
gtk_window_free_key_hash(GtkWindow * window)8269 gtk_window_free_key_hash (GtkWindow *window)
8270 {
8271 GtkKeyHash *key_hash = g_object_get_qdata (G_OBJECT (window), quark_gtk_window_key_hash);
8272 if (key_hash)
8273 {
8274 _gtk_key_hash_free (key_hash);
8275 g_object_set_qdata (G_OBJECT (window), quark_gtk_window_key_hash, NULL);
8276 }
8277 }
8278
8279 /**
8280 * gtk_window_activate_key:
8281 * @window: a #GtkWindow
8282 * @event: a #GdkEventKey
8283 *
8284 * Activates mnemonics and accelerators for this #GtkWindow. This is normally
8285 * called by the default ::key_press_event handler for toplevel windows,
8286 * however in some cases it may be useful to call this directly when
8287 * overriding the standard key handling for a toplevel window.
8288 *
8289 * Return value: %TRUE if a mnemonic or accelerator was found and activated.
8290 *
8291 * Since: 2.4
8292 */
8293 gboolean
gtk_window_activate_key(GtkWindow * window,GdkEventKey * event)8294 gtk_window_activate_key (GtkWindow *window,
8295 GdkEventKey *event)
8296 {
8297 GtkKeyHash *key_hash;
8298 GtkWindowKeyEntry *found_entry = NULL;
8299 gboolean enable_mnemonics;
8300 gboolean enable_accels;
8301
8302 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8303 g_return_val_if_fail (event != NULL, FALSE);
8304
8305 key_hash = gtk_window_get_key_hash (window);
8306
8307 if (key_hash)
8308 {
8309 GSList *tmp_list;
8310 GSList *entries = _gtk_key_hash_lookup (key_hash,
8311 event->hardware_keycode,
8312 event->state,
8313 gtk_accelerator_get_default_mod_mask (),
8314 event->group);
8315
8316 g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
8317 "gtk-enable-mnemonics", &enable_mnemonics,
8318 "gtk-enable-accels", &enable_accels,
8319 NULL);
8320
8321 for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
8322 {
8323 GtkWindowKeyEntry *entry = tmp_list->data;
8324 if (entry->is_mnemonic)
8325 {
8326 if (enable_mnemonics)
8327 {
8328 found_entry = entry;
8329 break;
8330 }
8331 }
8332 else
8333 {
8334 if (enable_accels && !found_entry)
8335 {
8336 found_entry = entry;
8337 }
8338 }
8339 }
8340
8341 g_slist_free (entries);
8342 }
8343
8344 if (found_entry)
8345 {
8346 if (found_entry->is_mnemonic)
8347 {
8348 if (enable_mnemonics)
8349 return gtk_window_mnemonic_activate (window, found_entry->keyval,
8350 found_entry->modifiers);
8351 }
8352 else
8353 {
8354 if (enable_accels)
8355 return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval,
8356 found_entry->modifiers);
8357 }
8358 }
8359
8360 return FALSE;
8361 }
8362
8363 static void
window_update_has_focus(GtkWindow * window)8364 window_update_has_focus (GtkWindow *window)
8365 {
8366 GtkWidget *widget = GTK_WIDGET (window);
8367 gboolean has_focus = window->has_toplevel_focus && window->is_active;
8368
8369 if (has_focus != window->has_focus)
8370 {
8371 window->has_focus = has_focus;
8372
8373 if (has_focus)
8374 {
8375 if (window->focus_widget &&
8376 window->focus_widget != widget &&
8377 !gtk_widget_has_focus (window->focus_widget))
8378 do_focus_change (window->focus_widget, TRUE);
8379 }
8380 else
8381 {
8382 if (window->focus_widget &&
8383 window->focus_widget != widget &&
8384 gtk_widget_has_focus (window->focus_widget))
8385 do_focus_change (window->focus_widget, FALSE);
8386 }
8387 }
8388 }
8389
8390 /**
8391 * _gtk_window_set_is_active:
8392 * @window: a #GtkWindow
8393 * @is_active: %TRUE if the window is in the currently active toplevel
8394 *
8395 * Internal function that sets whether the #GtkWindow is part
8396 * of the currently active toplevel window (taking into account inter-process
8397 * embedding.)
8398 **/
8399 void
_gtk_window_set_is_active(GtkWindow * window,gboolean is_active)8400 _gtk_window_set_is_active (GtkWindow *window,
8401 gboolean is_active)
8402 {
8403 g_return_if_fail (GTK_IS_WINDOW (window));
8404
8405 is_active = is_active != FALSE;
8406
8407 if (is_active != window->is_active)
8408 {
8409 window->is_active = is_active;
8410 window_update_has_focus (window);
8411
8412 g_object_notify (G_OBJECT (window), "is-active");
8413 }
8414 }
8415
8416 /**
8417 * _gtk_window_set_is_toplevel:
8418 * @window: a #GtkWindow
8419 * @is_toplevel: %TRUE if the window is still a real toplevel (nominally a
8420 * parent of the root window); %FALSE if it is not (for example, for an
8421 * in-process, parented GtkPlug)
8422 *
8423 * Internal function used by #GtkPlug when it gets parented/unparented by a
8424 * #GtkSocket. This keeps the @window's #GTK_TOPLEVEL flag in sync with the
8425 * global list of toplevel windows.
8426 */
8427 void
_gtk_window_set_is_toplevel(GtkWindow * window,gboolean is_toplevel)8428 _gtk_window_set_is_toplevel (GtkWindow *window,
8429 gboolean is_toplevel)
8430 {
8431 GtkWidget *widget;
8432
8433 widget = GTK_WIDGET (window);
8434
8435 if (gtk_widget_is_toplevel (widget))
8436 g_assert (g_slist_find (toplevel_list, window) != NULL);
8437 else
8438 g_assert (g_slist_find (toplevel_list, window) == NULL);
8439
8440 if (is_toplevel == gtk_widget_is_toplevel (widget))
8441 return;
8442
8443 if (is_toplevel)
8444 {
8445 _gtk_widget_set_is_toplevel (widget, TRUE);
8446 toplevel_list = g_slist_prepend (toplevel_list, window);
8447 }
8448 else
8449 {
8450 _gtk_widget_set_is_toplevel (widget, FALSE);
8451 toplevel_list = g_slist_remove (toplevel_list, window);
8452 }
8453 }
8454
8455 /**
8456 * _gtk_window_set_has_toplevel_focus:
8457 * @window: a #GtkWindow
8458 * @has_toplevel_focus: %TRUE if the in
8459 *
8460 * Internal function that sets whether the keyboard focus for the
8461 * toplevel window (taking into account inter-process embedding.)
8462 **/
8463 void
_gtk_window_set_has_toplevel_focus(GtkWindow * window,gboolean has_toplevel_focus)8464 _gtk_window_set_has_toplevel_focus (GtkWindow *window,
8465 gboolean has_toplevel_focus)
8466 {
8467 g_return_if_fail (GTK_IS_WINDOW (window));
8468
8469 has_toplevel_focus = has_toplevel_focus != FALSE;
8470
8471 if (has_toplevel_focus != window->has_toplevel_focus)
8472 {
8473 window->has_toplevel_focus = has_toplevel_focus;
8474 window_update_has_focus (window);
8475
8476 g_object_notify (G_OBJECT (window), "has-toplevel-focus");
8477 }
8478 }
8479
8480 /**
8481 * gtk_window_set_auto_startup_notification:
8482 * @setting: %TRUE to automatically do startup notification
8483 *
8484 * By default, after showing the first #GtkWindow, GTK+ calls
8485 * gdk_notify_startup_complete(). Call this function to disable
8486 * the automatic startup notification. You might do this if your
8487 * first window is a splash screen, and you want to delay notification
8488 * until after your real main window has been shown, for example.
8489 *
8490 * In that example, you would disable startup notification
8491 * temporarily, show your splash screen, then re-enable it so that
8492 * showing the main window would automatically result in notification.
8493 *
8494 * Since: 2.2
8495 **/
8496 void
gtk_window_set_auto_startup_notification(gboolean setting)8497 gtk_window_set_auto_startup_notification (gboolean setting)
8498 {
8499 disable_startup_notification = !setting;
8500 }
8501
8502 /**
8503 * gtk_window_get_window_type:
8504 * @window: a #GtkWindow
8505 *
8506 * Gets the type of the window. See #GtkWindowType.
8507 *
8508 * Return value: the type of the window
8509 *
8510 * Since: 2.20
8511 **/
8512 GtkWindowType
gtk_window_get_window_type(GtkWindow * window)8513 gtk_window_get_window_type (GtkWindow *window)
8514 {
8515 g_return_val_if_fail (GTK_IS_WINDOW (window), GTK_WINDOW_TOPLEVEL);
8516
8517 return window->type;
8518 }
8519
8520 /* gtk_window_get_mnemonics_visible:
8521 * @window: a #GtkWindow
8522 *
8523 * Gets the value of the #GtkWindow:mnemonics-visible property.
8524 *
8525 * Returns: %TRUE if mnemonics are supposed to be visible
8526 * in this window.
8527 *
8528 * Since: 2.20
8529 */
8530 gboolean
gtk_window_get_mnemonics_visible(GtkWindow * window)8531 gtk_window_get_mnemonics_visible (GtkWindow *window)
8532 {
8533 GtkWindowPrivate *priv;
8534
8535 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8536
8537 priv = GTK_WINDOW_GET_PRIVATE (window);
8538
8539 return priv->mnemonics_visible;
8540 }
8541
8542 /**
8543 * gtk_window_set_mnemonics_visible:
8544 * @window: a #GtkWindow
8545 * @setting: the new value
8546 *
8547 * Sets the #GtkWindow:mnemonics-visible property.
8548 *
8549 * Since: 2.20
8550 */
8551 void
gtk_window_set_mnemonics_visible(GtkWindow * window,gboolean setting)8552 gtk_window_set_mnemonics_visible (GtkWindow *window,
8553 gboolean setting)
8554 {
8555 GtkWindowPrivate *priv;
8556
8557 g_return_if_fail (GTK_IS_WINDOW (window));
8558
8559 priv = GTK_WINDOW_GET_PRIVATE (window);
8560
8561 setting = setting != FALSE;
8562
8563 if (priv->mnemonics_visible != setting)
8564 {
8565 priv->mnemonics_visible = setting;
8566 g_object_notify (G_OBJECT (window), "mnemonics-visible");
8567 }
8568
8569 priv->mnemonics_visible_set = TRUE;
8570 }
8571
8572 #if defined (G_OS_WIN32) && !defined (_WIN64)
8573
8574 #undef gtk_window_set_icon_from_file
8575
8576 gboolean
gtk_window_set_icon_from_file(GtkWindow * window,const gchar * filename,GError ** err)8577 gtk_window_set_icon_from_file (GtkWindow *window,
8578 const gchar *filename,
8579 GError **err)
8580 {
8581 gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, err);
8582 gboolean retval;
8583
8584 if (utf8_filename == NULL)
8585 return FALSE;
8586
8587 retval = gtk_window_set_icon_from_file_utf8 (window, utf8_filename, err);
8588
8589 g_free (utf8_filename);
8590
8591 return retval;
8592 }
8593
8594 #undef gtk_window_set_default_icon_from_file
8595
8596 gboolean
gtk_window_set_default_icon_from_file(const gchar * filename,GError ** err)8597 gtk_window_set_default_icon_from_file (const gchar *filename,
8598 GError **err)
8599 {
8600 gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, err);
8601 gboolean retval;
8602
8603 if (utf8_filename == NULL)
8604 return FALSE;
8605
8606 retval = gtk_window_set_default_icon_from_file_utf8 (utf8_filename, err);
8607
8608 g_free (utf8_filename);
8609
8610 return retval;
8611 }
8612
8613 #endif
8614
8615 #define __GTK_WINDOW_C__
8616 #include "gtkaliasdef.c"
8617