X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkwindow.c;h=1d3dfea02395aa8a6caa6f1cfae7e200fd77622a;hb=6669d0c581baced1feed0c0df587b96d72c386f1;hp=224a50129cbf3e4975d5551b04f7bd70e69056d4;hpb=6dc3eb34c2d7094e0e622c34b03474872c8da38d;p=~andy%2Fgtk diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 224a50129..1d3dfea02 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -31,14 +31,15 @@ #include "gtkprivate.h" #include "gtkrc.h" -#include "gtksignal.h" #include "gtkwindow.h" #include "gtkwindow-decorate.h" #include "gtkbindings.h" +#include "gtkkeyhash.h" #include "gtkmain.h" #include "gtkiconfactory.h" #include "gtkintl.h" #include "gtkmarshalers.h" +#include "gtkplug.h" enum { SET_FOCUS, @@ -67,6 +68,14 @@ enum { PROP_DEFAULT_HEIGHT, PROP_DESTROY_WITH_PARENT, PROP_ICON, + PROP_SCREEN, + PROP_TYPE_HINT, + PROP_SKIP_TASKBAR_HINT, + PROP_SKIP_PAGER_HINT, + + /* Readonly properties */ + PROP_IS_ACTIVE, + PROP_HAS_TOPLEVEL_FOCUS, LAST_ARG }; @@ -117,23 +126,40 @@ struct _GtkWindowGeometryInfo * we sent the last configure request. */ guint position_constraints_changed : 1; + + /* if true, default_width, height come from gtk_window_parse_geometry, + * and thus should be multiplied by the increments and affect the + * geometry widget only + */ + guint default_is_geometry : 1; GtkWindowLastGeometryInfo last; }; -typedef struct { +typedef struct _GtkWindowMnemonic GtkWindowMnemonic; + +struct _GtkWindowMnemonic { GtkWindow *window; guint keyval; GSList *targets; -} GtkWindowMnemonic; +}; +typedef struct _GtkWindowPrivate GtkWindowPrivate; + +struct _GtkWindowPrivate +{ + guint fullscreen_initially : 1; + guint skips_taskbar : 1; + guint skips_pager : 1; +}; static void gtk_window_class_init (GtkWindowClass *klass); static void gtk_window_init (GtkWindow *window); static void gtk_window_dispose (GObject *object); static void gtk_window_destroy (GtkObject *object); static void gtk_window_finalize (GObject *object); +static void gtk_window_private_finalize (GtkWindowPrivate *priv); static void gtk_window_show (GtkWidget *widget); static void gtk_window_hide (GtkWidget *widget); static void gtk_window_map (GtkWidget *widget); @@ -174,6 +200,7 @@ static void gtk_window_real_activate_default (GtkWindow *window); static void gtk_window_real_activate_focus (GtkWindow *window); static void gtk_window_move_focus (GtkWindow *window, GtkDirectionType dir); +static void gtk_window_keys_changed (GtkWindow *window); static void gtk_window_read_rcfiles (GtkWidget *widget, GdkEventClient *event); static void gtk_window_paint (GtkWidget *widget, @@ -186,6 +213,8 @@ static void gtk_window_transient_parent_realized (GtkWidget *parent, static void gtk_window_transient_parent_unrealized (GtkWidget *parent, GtkWidget *window); +static GdkScreen *gtk_window_check_screen (GtkWindow *window); + static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window, gboolean create); @@ -218,20 +247,24 @@ static void gtk_window_set_default_size_internal (GtkWindow *window, gboolean change_width, gint width, gboolean change_height, - gint height); + gint height, + gboolean is_geometry); static void gtk_window_realize_icon (GtkWindow *window); static void gtk_window_unrealize_icon (GtkWindow *window); -static void gtk_window_notify_keys_changed (GtkWindow *window); + +static void gtk_window_notify_keys_changed (GtkWindow *window); +static GtkKeyHash *gtk_window_get_key_hash (GtkWindow *window); +static void gtk_window_free_key_hash (GtkWindow *window); static GSList *toplevel_list = NULL; static GHashTable *mnemonic_hash_table = NULL; static GtkBinClass *parent_class = NULL; static guint window_signals[LAST_SIGNAL] = { 0 }; static GList *default_icon_list = NULL; -/* FIXME need to be per-screen */ -static GdkPixmap *default_icon_pixmap = NULL; -static GdkPixmap *default_icon_mask = NULL; +static guint default_icon_serial = 0; +static gboolean disable_startup_notification = FALSE; +static gboolean sent_startup_notification = FALSE; static void gtk_window_set_property (GObject *object, guint prop_id, @@ -272,31 +305,95 @@ mnemonic_equal (gconstpointer a, gconstpointer b) (ka->keyval == kb->keyval); } -GtkType +GtkWindowPrivate* +gtk_window_get_private (GtkWindow *window) +{ + GtkWindowPrivate *private; + static GQuark private_quark = 0; + + if (!private_quark) + private_quark = g_quark_from_static_string ("gtk-window-private"); + + private = g_object_get_qdata (G_OBJECT (window), private_quark); + + if (!private) + { + private = g_new0 (GtkWindowPrivate, 1); + + private->fullscreen_initially = FALSE; + private->skips_pager = FALSE; + private->skips_taskbar = FALSE; + + g_object_set_qdata_full (G_OBJECT (window), private_quark, + private, + (GDestroyNotify) gtk_window_private_finalize); + } + + return private; +} + +GType gtk_window_get_type (void) { - static GtkType window_type = 0; + static GType window_type = 0; if (!window_type) { - static const GtkTypeInfo window_info = + static const GTypeInfo window_info = { - "GtkWindow", - sizeof (GtkWindow), sizeof (GtkWindowClass), - (GtkClassInitFunc) gtk_window_class_init, - (GtkObjectInitFunc) gtk_window_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_window_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkWindow), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_window_init, }; - window_type = gtk_type_unique (gtk_bin_get_type (), &window_info); + window_type = g_type_register_static (GTK_TYPE_BIN, "GtkWindow", + &window_info, 0); } return window_type; } +static void +add_tab_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + GtkDirectionType direction) +{ + gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); +} + +static void +add_arrow_bindings (GtkBindingSet *binding_set, + guint keysym, + GtkDirectionType direction) +{ + guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left; + + gtk_binding_entry_add_signal (binding_set, keysym, 0, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK, + "move_focus", 1, + GTK_TYPE_DIRECTION_TYPE, direction); +} + + static void gtk_window_class_init (GtkWindowClass *klass) { @@ -310,7 +407,7 @@ gtk_window_class_init (GtkWindowClass *klass) widget_class = (GtkWidgetClass*) klass; container_class = (GtkContainerClass*) klass; - parent_class = gtk_type_class (gtk_bin_get_type ()); + parent_class = g_type_class_peek_parent (klass); mnemonic_hash_table = g_hash_table_new (mnemonic_hash, mnemonic_equal); @@ -350,7 +447,7 @@ gtk_window_class_init (GtkWindowClass *klass) klass->activate_default = gtk_window_real_activate_default; klass->activate_focus = gtk_window_real_activate_focus; klass->move_focus = gtk_window_move_focus; - klass->keys_changed = NULL; + klass->keys_changed = gtk_window_keys_changed; /* Construct */ g_object_class_install_property (gobject_class, @@ -376,7 +473,7 @@ gtk_window_class_init (GtkWindowClass *klass) g_param_spec_boolean ("allow_shrink", _("Allow Shrink"), /* xgettext:no-c-format */ - _("If TRUE, the window has no mimimum size. Setting this to TRUE is 99% of the time a bad idea."), + _("If TRUE, the window has no mimimum size. Setting this to TRUE is 99% of the time a bad idea"), FALSE, G_PARAM_READWRITE)); @@ -384,7 +481,7 @@ gtk_window_class_init (GtkWindowClass *klass) PROP_ALLOW_GROW, g_param_spec_boolean ("allow_grow", _("Allow Grow"), - _("If TRUE, users can expand the window beyond its minimum size."), + _("If TRUE, users can expand the window beyond its minimum size"), TRUE, G_PARAM_READWRITE)); @@ -392,7 +489,7 @@ gtk_window_class_init (GtkWindowClass *klass) PROP_RESIZABLE, g_param_spec_boolean ("resizable", _("Resizable"), - _("If TRUE, users can resize the window."), + _("If TRUE, users can resize the window"), TRUE, G_PARAM_READWRITE)); @@ -400,7 +497,7 @@ gtk_window_class_init (GtkWindowClass *klass) PROP_MODAL, g_param_spec_boolean ("modal", _("Modal"), - _("If TRUE, the window is modal (other windows are not usable while this one is up)."), + _("If TRUE, the window is modal (other windows are not usable while this one is up)"), FALSE, G_PARAM_READWRITE)); @@ -408,7 +505,7 @@ gtk_window_class_init (GtkWindowClass *klass) PROP_WIN_POS, g_param_spec_enum ("window_position", _("Window Position"), - _("The initial position of the window."), + _("The initial position of the window"), GTK_TYPE_WINDOW_POSITION, GTK_WIN_POS_NONE, G_PARAM_READWRITE)); @@ -417,7 +514,7 @@ gtk_window_class_init (GtkWindowClass *klass) PROP_DEFAULT_WIDTH, g_param_spec_int ("default_width", _("Default Width"), - _("The default width of the window, used when initially showing the window."), + _("The default width of the window, used when initially showing the window"), -1, G_MAXINT, -1, @@ -427,7 +524,7 @@ gtk_window_class_init (GtkWindowClass *klass) PROP_DEFAULT_HEIGHT, g_param_spec_int ("default_height", _("Default Height"), - _("The default height of the window, used when initially showing the window."), + _("The default height of the window, used when initially showing the window"), -1, G_MAXINT, -1, @@ -449,9 +546,58 @@ gtk_window_class_init (GtkWindowClass *klass) GDK_TYPE_PIXBUF, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_SCREEN, + g_param_spec_object ("screen", + _("Screen"), + _("The screen where this window will be displayed"), + GDK_TYPE_SCREEN, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_IS_ACTIVE, + g_param_spec_boolean ("is_active", + _("Is Active"), + _("Whether the toplevel is the current active window"), + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_HAS_TOPLEVEL_FOCUS, + g_param_spec_boolean ("has_toplevel_focus", + _("Focus in Toplevel"), + _("Whether the input focus is within this GtkWindow"), + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_TYPE_HINT, + g_param_spec_enum ("type_hint", + _("Type hint"), + _("Hint to help the desktop environment understand what kind of window this is and how to treat it."), + GDK_TYPE_WINDOW_TYPE_HINT, + GDK_WINDOW_TYPE_HINT_NORMAL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SKIP_TASKBAR_HINT, + g_param_spec_boolean ("skip_taskbar_hint", + _("Skip taskbar"), + _("TRUE if the window should not be in the task bar."), + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SKIP_PAGER_HINT, + g_param_spec_boolean ("skip_pager_hint", + _("Skip pager"), + _("TRUE if the window should not be in the pager."), + FALSE, + G_PARAM_READWRITE)); + window_signals[SET_FOCUS] = g_signal_new ("set_focus", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GtkWindowClass, set_focus), NULL, NULL, @@ -461,7 +607,7 @@ gtk_window_class_init (GtkWindowClass *klass) window_signals[FRAME_EVENT] = g_signal_new ("frame_event", - G_TYPE_FROM_CLASS(object_class), + G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkWindowClass, frame_event), _gtk_boolean_handled_accumulator, NULL, @@ -471,9 +617,9 @@ gtk_window_class_init (GtkWindowClass *klass) window_signals[ACTIVATE_FOCUS] = g_signal_new ("activate_focus", - G_OBJECT_CLASS_TYPE (object_class), + G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - GTK_SIGNAL_OFFSET (GtkWindowClass, activate_focus), + G_STRUCT_OFFSET (GtkWindowClass, activate_focus), NULL, NULL, _gtk_marshal_VOID__VOID, G_TYPE_NONE, @@ -481,9 +627,9 @@ gtk_window_class_init (GtkWindowClass *klass) window_signals[ACTIVATE_DEFAULT] = g_signal_new ("activate_default", - G_OBJECT_CLASS_TYPE (object_class), + G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - GTK_SIGNAL_OFFSET (GtkWindowClass, activate_default), + G_STRUCT_OFFSET (GtkWindowClass, activate_default), NULL, NULL, _gtk_marshal_VOID__VOID, G_TYPE_NONE, @@ -491,9 +637,9 @@ gtk_window_class_init (GtkWindowClass *klass) window_signals[MOVE_FOCUS] = g_signal_new ("move_focus", - G_OBJECT_CLASS_TYPE (object_class), + G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - GTK_SIGNAL_OFFSET (GtkWindowClass, move_focus), + G_STRUCT_OFFSET (GtkWindowClass, move_focus), NULL, NULL, _gtk_marshal_VOID__ENUM, G_TYPE_NONE, @@ -502,11 +648,11 @@ gtk_window_class_init (GtkWindowClass *klass) window_signals[KEYS_CHANGED] = g_signal_new ("keys_changed", - G_OBJECT_CLASS_TYPE (object_class), + G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_FIRST, - GTK_SIGNAL_OFFSET (GtkWindowClass, keys_changed), + G_STRUCT_OFFSET (GtkWindowClass, keys_changed), NULL, NULL, - gtk_marshal_VOID__VOID, + _gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); @@ -527,53 +673,15 @@ gtk_window_class_init (GtkWindowClass *klass) gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "activate_default", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP); - - gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN); - - gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT); - - gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT); - - gtk_binding_entry_add_signal (binding_set, GDK_Tab, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, 0, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD); + add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP); + add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN); + add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT); + add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT); - gtk_binding_entry_add_signal (binding_set, GDK_Tab, GDK_SHIFT_MASK, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_SHIFT_MASK, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, GDK_SHIFT_MASK, - "move_focus", 1, - GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD); + add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD); + add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD); + add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD); + add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD); } static void @@ -614,22 +722,23 @@ gtk_window_init (GtkWindow *window) window->gravity = GDK_GRAVITY_NORTH_WEST; window->decorated = TRUE; window->mnemonic_modifier = GDK_MOD1_MASK; + window->screen = gdk_screen_get_default (); colormap = _gtk_widget_peek_colormap (); if (colormap) gtk_widget_set_colormap (GTK_WIDGET (window), colormap); - gtk_widget_ref (GTK_WIDGET (window)); + g_object_ref (window); gtk_object_sink (GTK_OBJECT (window)); window->has_user_ref_count = TRUE; toplevel_list = g_slist_prepend (toplevel_list, window); gtk_decorated_window_init (window); - gtk_signal_connect (GTK_OBJECT (window), - "event", - GTK_SIGNAL_FUNC (gtk_window_event), - NULL); + g_signal_connect (window, + "event", + G_CALLBACK (gtk_window_event), + NULL); } static void @@ -673,12 +782,12 @@ gtk_window_set_property (GObject *object, case PROP_DEFAULT_WIDTH: gtk_window_set_default_size_internal (window, TRUE, g_value_get_int (value), - FALSE, -1); + FALSE, -1, FALSE); break; case PROP_DEFAULT_HEIGHT: gtk_window_set_default_size_internal (window, FALSE, -1, - TRUE, g_value_get_int (value)); + TRUE, g_value_get_int (value), FALSE); break; case PROP_DESTROY_WITH_PARENT: gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value)); @@ -687,7 +796,22 @@ gtk_window_set_property (GObject *object, gtk_window_set_icon (window, g_value_get_object (value)); break; - + case PROP_SCREEN: + gtk_window_set_screen (window, g_value_get_object (value)); + break; + case PROP_TYPE_HINT: + gtk_window_set_type_hint (window, + g_value_get_enum (value)); + break; + case PROP_SKIP_TASKBAR_HINT: + gtk_window_set_skip_taskbar_hint (window, + g_value_get_boolean (value)); + break; + case PROP_SKIP_PAGER_HINT: + gtk_window_set_skip_pager_hint (window, + g_value_get_boolean (value)); + break; + default: break; } @@ -747,6 +871,27 @@ gtk_window_get_property (GObject *object, case PROP_ICON: g_value_set_object (value, gtk_window_get_icon (window)); break; + case PROP_SCREEN: + g_value_set_object (value, window->screen); + break; + case PROP_IS_ACTIVE: + g_value_set_boolean (value, window->is_active); + break; + case PROP_HAS_TOPLEVEL_FOCUS: + g_value_set_boolean (value, window->has_toplevel_focus); + break; + case PROP_TYPE_HINT: + g_value_set_enum (value, + window->type_hint); + break; + case PROP_SKIP_TASKBAR_HINT: + g_value_set_boolean (value, + gtk_window_get_skip_taskbar_hint (window)); + break; + case PROP_SKIP_PAGER_HINT: + g_value_set_boolean (value, + gtk_window_get_skip_pager_hint (window)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -764,7 +909,8 @@ gtk_window_get_property (GObject *object, * you might use #GTK_WINDOW_POPUP. #GTK_WINDOW_POPUP is not for * dialogs, though in some other toolkits dialogs are called "popups". * In GTK+, #GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip. - * Popup windows are not controlled by the window manager. + * On X11, popup windows are not controlled by the window manager. * * If you simply want an undecorated window (no window borders), use * gtk_window_set_decorated(), don't use #GTK_WINDOW_POPUP. @@ -778,7 +924,7 @@ gtk_window_new (GtkWindowType type) g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL); - window = gtk_type_new (GTK_TYPE_WINDOW); + window = g_object_new (GTK_TYPE_WINDOW, NULL); window->type = type; @@ -790,12 +936,14 @@ gtk_window_new (GtkWindowType type) * @window: a #GtkWindow * @title: title of the window * - * Sets the title of the #GtkWindow. The title of a window will be displayed in - * its title bar; on the X Window System, the title bar is rendered by the - * window manager, so exactly how the title appears to users may vary according - * to a user's exact configuration. The title should help a user distinguish - * this window from other windows they may have open. A good title might - * include the application name and current document filename, for example. + * Sets the title of the #GtkWindow. The title of a window will be + * displayed in its title bar; on the X Window System, the title bar + * is rendered by the window + * manager, so exactly how the title appears to users may vary + * according to a user's exact configuration. The title should help a + * user distinguish this window from other windows they may have + * open. A good title might include the application name and current + * document filename, for example. * **/ void @@ -874,11 +1022,14 @@ gtk_window_set_wmclass (GtkWindow *window, * @window: a #GtkWindow * @role: unique identifier for the window to be used when restoring a session * + * This function is only useful on X11, not with other GTK+ targets. + * * In combination with the window title, the window role allows a - * window manager to identify "the same" window when an application is - * restarted. So for example you might set the "toolbox" role on your - * app's toolbox window, so that when the user restarts their session, - * the window manager can put the toolbox back in the same place. + * window manager to identify "the + * same" window when an application is restarted. So for example you + * might set the "toolbox" role on your app's toolbox window, so that + * when the user restarts their session, the window manager can put + * the toolbox back in the same place. * * If a window already has a unique title, you don't need to set the * role, since the WM can use the title to identify the window when @@ -946,7 +1097,22 @@ gtk_window_set_focus (GtkWindow *window, if (focus) gtk_widget_grab_focus (focus); else - _gtk_window_internal_set_focus (window, NULL); + { + /* Clear the existing focus chain, so that when we focus into + * the window again, we start at the beginnning. + */ + GtkWidget *widget = window->focus_widget; + if (widget) + { + while (widget->parent) + { + widget = widget->parent; + gtk_container_set_focus_child (GTK_CONTAINER (widget), NULL); + } + } + + _gtk_window_internal_set_focus (window, NULL); + } } void @@ -957,7 +1123,7 @@ _gtk_window_internal_set_focus (GtkWindow *window, if ((window->focus_widget != focus) || (focus && !GTK_WIDGET_HAS_FOCUS (focus))) - gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus); + g_signal_emit (window, window_signals[SET_FOCUS], 0, focus); } /** @@ -1102,14 +1268,22 @@ gtk_window_remove_accel_group (GtkWindow *window, GtkAccelGroup *accel_group) { g_return_if_fail (GTK_IS_WINDOW (window)); - g_return_if_fail (accel_group != NULL); + g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group)); g_signal_handlers_disconnect_by_func (accel_group, - G_CALLBACK (gtk_window_notify_keys_changed), + gtk_window_notify_keys_changed, window); _gtk_accel_group_detach (accel_group, G_OBJECT (window)); } +/** + * gtk_window_add_mnemonic: + * @window: a #GtkWindow + * @keyval: the mnemonic + * @target: the widget that gets activated by the mnemonic + * + * Adds a mnemonic to this window. + */ void gtk_window_add_mnemonic (GtkWindow *window, guint keyval, @@ -1128,7 +1302,7 @@ gtk_window_add_mnemonic (GtkWindow *window, if (mnemonic) { g_return_if_fail (g_slist_find (mnemonic->targets, target) == NULL); - mnemonic->targets = g_slist_prepend (mnemonic->targets, target); + mnemonic->targets = g_slist_append (mnemonic->targets, target); } else { @@ -1140,6 +1314,14 @@ gtk_window_add_mnemonic (GtkWindow *window, gtk_window_notify_keys_changed (window); } +/** + * gtk_window_remove_mnemonic: + * @window: a #GtkWindow + * @keyval: the mnemonic + * @target: the widget that gets activated by the mnemonic + * + * Removes a mnemonic from this window. + */ void gtk_window_remove_mnemonic (GtkWindow *window, guint keyval, @@ -1166,6 +1348,15 @@ gtk_window_remove_mnemonic (GtkWindow *window, gtk_window_notify_keys_changed (window); } +/** + * gtk_window_mnemonic_activate: + * @window: a #GtkWindow + * @keyval: the mnemonic + * @modifier: the modifiers + * @returns: %TRUE if the activation is done. + * + * Activates the targets associated with the mnemonic. + */ gboolean gtk_window_mnemonic_activate (GtkWindow *window, guint keyval, @@ -1296,6 +1487,14 @@ gtk_window_set_position (GtkWindow *window, g_object_notify (G_OBJECT (window), "window_position"); } +/** + * gtk_window_activate_focus: + * @window: a #GtkWindow + * + * Activates the current focused widget within the window. + * + * Return value: %TRUE if a widget got activated. + **/ gboolean gtk_window_activate_focus (GtkWindow *window) { @@ -1331,6 +1530,17 @@ gtk_window_get_focus (GtkWindow *window) return window->focus_widget; } +/** + * gtk_window_activate_default: + * @window: a #GtkWindow + * + * Activates the default widget for the window, unless the current + * focused widget has been configured to receive the default action + * (see #GTK_RECEIVES_DEFAULT in #GtkWidgetFlags), in which case the + * focused widget is activated. + * + * Return value: %TRUE if a widget got activated. + **/ gboolean gtk_window_activate_default (GtkWindow *window) { @@ -1361,8 +1571,8 @@ gtk_window_activate_default (GtkWindow *window) * with other windows in the same application. To keep modal dialogs * on top of main application windows, use * gtk_window_set_transient_for() to make the dialog transient for the - * parent; most window managers will then disallow lowering the dialog - * below the parent. + * parent; most window managers + * will then disallow lowering the dialog below the parent. * * **/ @@ -1372,13 +1582,30 @@ gtk_window_set_modal (GtkWindow *window, { g_return_if_fail (GTK_IS_WINDOW (window)); - window->modal = modal != FALSE; + modal = modal != FALSE; + if (window->modal == modal) + return; + + window->modal = modal; /* adjust desired modality state */ - if (GTK_WIDGET_VISIBLE (window) && window->modal) - gtk_grab_add (GTK_WIDGET (window)); - else - gtk_grab_remove (GTK_WIDGET (window)); + if (GTK_WIDGET_REALIZED (window)) + { + GtkWidget *widget = GTK_WIDGET (window); + + if (window->modal) + gdk_window_set_modal_hint (widget->window, TRUE); + else + gdk_window_set_modal_hint (widget->window, FALSE); + } + + if (GTK_WIDGET_VISIBLE (window)) + { + if (window->modal) + gtk_grab_add (GTK_WIDGET (window)); + else + gtk_grab_remove (GTK_WIDGET (window)); + } g_object_notify (G_OBJECT (window), "modal"); } @@ -1431,17 +1658,17 @@ gtk_window_add_embedded_xid (GtkWindow *window, guint xid) g_return_if_fail (GTK_IS_WINDOW (window)); - embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded"); + embedded_windows = g_object_get_data (G_OBJECT (window), "gtk-embedded"); if (embedded_windows) - gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), - g_quark_from_static_string ("gtk-embedded")); + g_object_steal_qdata (G_OBJECT (window), + g_quark_from_static_string ("gtk-embedded")); embedded_windows = g_list_prepend (embedded_windows, GUINT_TO_POINTER (xid)); - gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded", - embedded_windows, - embedded_windows ? - (GtkDestroyNotify) g_list_free : NULL); + g_object_set_data_full (G_OBJECT (window), "gtk-embedded", + embedded_windows, + embedded_windows ? + (GDestroyNotify) g_list_free : NULL); } void @@ -1452,10 +1679,10 @@ gtk_window_remove_embedded_xid (GtkWindow *window, guint xid) g_return_if_fail (GTK_IS_WINDOW (window)); - embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded"); + embedded_windows = g_object_get_data (G_OBJECT (window), "gtk-embedded"); if (embedded_windows) - gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), - g_quark_from_static_string ("gtk-embedded")); + g_object_steal_qdata (G_OBJECT (window), + g_quark_from_static_string ("gtk-embedded")); node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid)); if (node) @@ -1464,10 +1691,10 @@ gtk_window_remove_embedded_xid (GtkWindow *window, guint xid) g_list_free_1 (node); } - gtk_object_set_data_full (GTK_OBJECT (window), - "gtk-embedded", embedded_windows, - embedded_windows ? - (GtkDestroyNotify) g_list_free : NULL); + g_object_set_data_full (G_OBJECT (window), "gtk-embedded", + embedded_windows, + embedded_windows ? + (GDestroyNotify) g_list_free : NULL); } void @@ -1483,11 +1710,7 @@ _gtk_window_reposition (GtkWindow *window, static void gtk_window_dispose (GObject *object) { - GtkWindow *window; - - g_return_if_fail (GTK_IS_WINDOW (object)); - - window = GTK_WINDOW (object); + GtkWindow *window = GTK_WINDOW (object); gtk_window_set_focus (window, NULL); gtk_window_set_default (window, NULL); @@ -1506,10 +1729,10 @@ connect_parent_destroyed (GtkWindow *window) { if (window->transient_parent) { - gtk_signal_connect (GTK_OBJECT (window->transient_parent), - "destroy", - GTK_SIGNAL_FUNC (parent_destroyed_callback), - window); + g_signal_connect (window->transient_parent, + "destroy", + G_CALLBACK (parent_destroyed_callback), + window); } } @@ -1518,9 +1741,9 @@ disconnect_parent_destroyed (GtkWindow *window) { if (window->transient_parent) { - gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent), - GTK_SIGNAL_FUNC (parent_destroyed_callback), - window); + g_signal_handlers_disconnect_by_func (window->transient_parent, + parent_destroyed_callback, + window); } } @@ -1541,20 +1764,31 @@ gtk_window_transient_parent_unrealized (GtkWidget *parent, gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE)); } +static void +gtk_window_transient_parent_screen_changed (GtkWindow *parent, + GParamSpec *pspec, + GtkWindow *window) +{ + gtk_window_set_screen (window, parent->screen); +} + static void gtk_window_unset_transient_for (GtkWindow *window) { if (window->transient_parent) { - gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent), - GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized), - window); - gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent), - GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized), - window); - gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent), - GTK_SIGNAL_FUNC (gtk_widget_destroyed), - &window->transient_parent); + g_signal_handlers_disconnect_by_func (window->transient_parent, + gtk_window_transient_parent_realized, + window); + g_signal_handlers_disconnect_by_func (window->transient_parent, + gtk_window_transient_parent_unrealized, + window); + g_signal_handlers_disconnect_by_func (window->transient_parent, + gtk_window_transient_parent_screen_changed, + window); + g_signal_handlers_disconnect_by_func (window->transient_parent, + gtk_widget_destroyed, + &window->transient_parent); if (window->destroy_with_parent) disconnect_parent_destroyed (window); @@ -1569,11 +1803,16 @@ gtk_window_unset_transient_for (GtkWindow *window) * @parent: parent window * * Dialog windows should be set transient for the main application - * window they were spawned from. This allows window managers to - * e.g. keep the dialog on top of the main window, or center the - * dialog over the main window. gtk_dialog_new_with_buttons() and - * other convenience functions in GTK+ will sometimes call + * window they were spawned from. This allows window managers to e.g. keep the + * dialog on top of the main window, or center the dialog over the + * main window. gtk_dialog_new_with_buttons() and other convenience + * functions in GTK+ will sometimes call * gtk_window_set_transient_for() on your behalf. + * + * On Windows, this function will and put the child window + * on top of the parent, much as the window manager would have + * done on X. * **/ void @@ -1600,15 +1839,20 @@ gtk_window_set_transient_for (GtkWindow *window, if (parent) { - gtk_signal_connect (GTK_OBJECT (parent), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroyed), - &window->transient_parent); - gtk_signal_connect (GTK_OBJECT (parent), "realize", - GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized), - window); - gtk_signal_connect (GTK_OBJECT (parent), "unrealize", - GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized), - window); + g_signal_connect (parent, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &window->transient_parent); + g_signal_connect (parent, "realize", + G_CALLBACK (gtk_window_transient_parent_realized), + window); + g_signal_connect (parent, "unrealize", + G_CALLBACK (gtk_window_transient_parent_unrealized), + window); + g_signal_connect (parent, "notify::screen", + G_CALLBACK (gtk_window_transient_parent_screen_changed), + window); + + gtk_window_set_screen (window, parent->screen); if (window->destroy_with_parent) connect_parent_destroyed (window); @@ -1678,6 +1922,117 @@ gtk_window_get_type_hint (GtkWindow *window) return window->type_hint; } +/** + * gtk_window_set_skip_taskbar_hint: + * @window: a #GtkWindow + * @setting: %TRUE to keep this window from appearing in the task bar + * + * Windows may set a hint asking the desktop environment not to display + * the window in the task bar. This function toggles this hint. + * + * Since: 2.2 + **/ +void +gtk_window_set_skip_taskbar_hint (GtkWindow *window, + gboolean setting) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = gtk_window_get_private (window); + + setting = setting != FALSE; + + if (priv->skips_taskbar != setting) + { + priv->skips_taskbar = setting; + if (GTK_WIDGET_REALIZED (window)) + gdk_window_set_skip_taskbar_hint (GTK_WIDGET (window)->window, + priv->skips_taskbar); + g_object_notify (G_OBJECT (window), "skip_taskbar_hint"); + } +} + +/** + * gtk_window_get_skip_taskbar_hint: + * @window: a #GtkWindow + * + * Gets the value set by gtk_window_set_skip_taskbar_hint() + * + * Return value: %TRUE if window shouldn't be in taskbar + * + * Since: 2.2 + **/ +gboolean +gtk_window_get_skip_taskbar_hint (GtkWindow *window) +{ + GtkWindowPrivate *priv; + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + priv = gtk_window_get_private (window); + + return priv->skips_taskbar; +} + +/** + * gtk_window_set_skip_pager_hint: + * @window: a #GtkWindow + * @setting: %TRUE to keep this window from appearing in the pager + * + * Windows may set a hint asking the desktop environment not to display + * the window in the pager. This function toggles this hint. + * (A "pager" is any desktop navigation tool such as a workspace + * switcher that displays a thumbnail representation of the windows + * on the screen.) + * + * Since: 2.2 + **/ +void +gtk_window_set_skip_pager_hint (GtkWindow *window, + gboolean setting) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = gtk_window_get_private (window); + + setting = setting != FALSE; + + if (priv->skips_pager != setting) + { + priv->skips_pager = setting; + if (GTK_WIDGET_REALIZED (window)) + gdk_window_set_skip_pager_hint (GTK_WIDGET (window)->window, + priv->skips_pager); + g_object_notify (G_OBJECT (window), "skip_pager_hint"); + } +} + +/** + * gtk_window_get_skip_pager_hint: + * @window: a #GtkWindow + * + * Gets the value set by gtk_window_set_skip_pager_hint(). + * + * Return value: %TRUE if window shouldn't be in pager + * + * Since: 2.2 + **/ +gboolean +gtk_window_get_skip_pager_hint (GtkWindow *window) +{ + GtkWindowPrivate *priv; + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + priv = gtk_window_get_private (window); + + return priv->skips_pager; +} + /** * gtk_window_set_destroy_with_parent: * @window: a #GtkWindow @@ -1746,6 +2101,7 @@ gtk_window_get_geometry_info (GtkWindow *window, info->initial_x = 0; info->initial_y = 0; info->initial_pos_set = FALSE; + info->default_is_geometry = FALSE; info->position_constraints_changed = FALSE; info->last.configure_request.x = 0; info->last.configure_request.y = 0; @@ -1780,20 +2136,21 @@ gtk_window_set_geometry_hints (GtkWindow *window, { GtkWindowGeometryInfo *info; - g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (geometry_widget == NULL || GTK_IS_WIDGET (geometry_widget)); info = gtk_window_get_geometry_info (window, TRUE); if (info->widget) - gtk_signal_disconnect_by_func (GTK_OBJECT (info->widget), - GTK_SIGNAL_FUNC (gtk_widget_destroyed), - &info->widget); + g_signal_handlers_disconnect_by_func (info->widget, + gtk_widget_destroyed, + &info->widget); info->widget = geometry_widget; if (info->widget) - gtk_signal_connect (GTK_OBJECT (geometry_widget), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroyed), - &info->widget); + g_signal_connect (geometry_widget, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &info->widget); if (geometry) info->geometry = *geometry; @@ -1815,10 +2172,16 @@ gtk_window_set_geometry_hints (GtkWindow *window, * @setting: %TRUE to decorate the window * * By default, windows are decorated with a title bar, resize - * controls, etc. Some window managers allow GTK+ to disable these - * decorations, creating a borderless window. If you set the decorated - * property to %FALSE using this function, GTK+ will do its best to - * convince the window manager not to decorate the window. + * controls, etc. Some window + * managers allow GTK+ to disable these decorations, creating a + * borderless window. If you set the decorated property to %FALSE + * using this function, GTK+ will do its best to convince the window + * manager not to decorate the window. Depending on the system, this + * function may not have any effect when called on a window that is + * already visible, so you should call it before calling gtk_window_show(). + * + * On Windows, this function always works, since there's no window manager + * policy involved. * **/ void @@ -1888,40 +2251,79 @@ ensure_icon_info (GtkWindow *window) return info; } +typedef struct { + guint serial; + GdkPixmap *pixmap; + GdkPixmap *mask; +} ScreenIconInfo; + +ScreenIconInfo * +get_screen_icon_info (GdkScreen *screen) +{ + ScreenIconInfo *info = g_object_get_data (G_OBJECT (screen), + "gtk-window-default-icon-pixmap"); + if (!info) + { + info = g_new0 (ScreenIconInfo, 1); + g_object_set_data (G_OBJECT (screen), "gtk-window-default-icon-pixmap", info); + } + + if (info->serial != default_icon_serial) + { + if (info->pixmap) + { + g_object_remove_weak_pointer (G_OBJECT (info->pixmap), (gpointer*)&info->pixmap); + info->pixmap = NULL; + } + + if (info->mask) + { + g_object_remove_weak_pointer (G_OBJECT (info->mask), (gpointer*)&info->mask); + info->mask = NULL; + } + + info->serial = default_icon_serial; + } + + return info; +} + static void -get_pixmap_and_mask (GtkWindowIconInfo *parent_info, +get_pixmap_and_mask (GdkWindow *window, + GtkWindowIconInfo *parent_info, gboolean is_default_list, GList *icon_list, GdkPixmap **pmap_return, GdkBitmap **mask_return) { + GdkScreen *screen = gdk_drawable_get_screen (window); + ScreenIconInfo *default_icon_info = get_screen_icon_info (screen); GdkPixbuf *best_icon; GList *tmp_list; int best_size; - + *pmap_return = NULL; *mask_return = NULL; if (is_default_list && - default_icon_pixmap != NULL) + default_icon_info->pixmap != NULL) { - /* Use shared icon pixmap (eventually will be stored on the - * GdkScreen) + /* Use shared icon pixmap for all windows on this screen. */ - if (default_icon_pixmap) - g_object_ref (G_OBJECT (default_icon_pixmap)); - if (default_icon_mask) - g_object_ref (G_OBJECT (default_icon_mask)); - - *pmap_return = default_icon_pixmap; - *mask_return = default_icon_mask; + if (default_icon_info->pixmap) + g_object_ref (default_icon_info->pixmap); + if (default_icon_info->mask) + g_object_ref (default_icon_info->mask); + + *pmap_return = default_icon_info->pixmap; + *mask_return = default_icon_info->mask; } else if (parent_info && parent_info->icon_pixmap) { if (parent_info->icon_pixmap) - g_object_ref (G_OBJECT (parent_info->icon_pixmap)); + g_object_ref (parent_info->icon_pixmap); if (parent_info->icon_mask) - g_object_ref (G_OBJECT (parent_info->icon_mask)); + g_object_ref (parent_info->icon_mask); *pmap_return = parent_info->icon_pixmap; *mask_return = parent_info->icon_mask; @@ -1968,7 +2370,7 @@ get_pixmap_and_mask (GtkWindowIconInfo *parent_info, if (best_icon) gdk_pixbuf_render_pixmap_and_mask_for_colormap (best_icon, - gdk_colormap_get_system (), + gdk_screen_get_system_colormap (screen), pmap_return, mask_return, 128); @@ -1980,21 +2382,21 @@ get_pixmap_and_mask (GtkWindowIconInfo *parent_info, parent_info->icon_mask = *mask_return; if (parent_info->icon_pixmap) - g_object_ref (G_OBJECT (parent_info->icon_pixmap)); + g_object_ref (parent_info->icon_pixmap); if (parent_info->icon_mask) - g_object_ref (G_OBJECT (parent_info->icon_mask)); + g_object_ref (parent_info->icon_mask); } else if (is_default_list) { - default_icon_pixmap = *pmap_return; - default_icon_mask = *mask_return; - - if (default_icon_pixmap) - g_object_add_weak_pointer (G_OBJECT (default_icon_pixmap), - (gpointer*)&default_icon_pixmap); - if (default_icon_mask) - g_object_add_weak_pointer (G_OBJECT (default_icon_mask), - (gpointer*)&default_icon_mask); + default_icon_info->pixmap = *pmap_return; + default_icon_info->mask = *mask_return; + + if (default_icon_info->pixmap) + g_object_add_weak_pointer (G_OBJECT (default_icon_info->pixmap), + (gpointer*)&default_icon_info->pixmap); + if (default_icon_info->mask) + g_object_add_weak_pointer (G_OBJECT (default_icon_info->mask), + (gpointer*)&default_icon_info->mask); } } } @@ -2047,8 +2449,8 @@ gtk_window_realize_icon (GtkWindow *window) gdk_window_set_icon_list (widget->window, icon_list); - get_pixmap_and_mask (info->using_parent_icon ? - ensure_icon_info (window->transient_parent) : NULL, + get_pixmap_and_mask (widget->window, + info->using_parent_icon ? ensure_icon_info (window->transient_parent) : NULL, info->using_default_icon, icon_list, &info->icon_pixmap, @@ -2079,10 +2481,10 @@ gtk_window_unrealize_icon (GtkWindow *window) return; if (info->icon_pixmap) - g_object_unref (G_OBJECT (info->icon_pixmap)); + g_object_unref (info->icon_pixmap); if (info->icon_mask) - g_object_unref (G_OBJECT (info->icon_mask)); + g_object_unref (info->icon_mask); info->icon_pixmap = NULL; info->icon_mask = NULL; @@ -2218,7 +2620,10 @@ gtk_window_set_icon (GtkWindow *window, g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon)); list = NULL; - list = g_list_append (list, icon); + + if (icon) + list = g_list_append (list, icon); + gtk_window_set_icon_list (window, list); g_list_free (list); } @@ -2238,6 +2643,8 @@ gtk_window_get_icon (GtkWindow *window) { GtkWindowIconInfo *info; + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + info = get_icon_info (window); if (info && info->icon_list) return GDK_PIXBUF (info->icon_list->data); @@ -2245,33 +2652,89 @@ gtk_window_get_icon (GtkWindow *window) return NULL; } -/** - * gtk_window_set_default_icon_list: - * @list: a list of #GdkPixbuf - * - * Sets an icon list to be used as fallback for windows that haven't - * had gtk_window_set_icon_list() called on them to set up a - * window-specific icon list. This function allows you to set up the - * icon for all windows in your app at once. - * - * See gtk_window_set_icon_list() for more details. - * - **/ -void -gtk_window_set_default_icon_list (GList *list) +/* Load pixbuf, printing warning on failure if error == NULL + */ +static GdkPixbuf * +load_pixbuf_verbosely (const char *filename, + GError **err) { - GList *toplevels; - GList *tmp_list; - if (list == default_icon_list) - return; + GError *local_err = NULL; + GdkPixbuf *pixbuf; - if (default_icon_pixmap) - g_object_unref (G_OBJECT (default_icon_pixmap)); - if (default_icon_mask) - g_object_unref (G_OBJECT (default_icon_mask)); + pixbuf = gdk_pixbuf_new_from_file (filename, &local_err); - default_icon_pixmap = NULL; - default_icon_mask = NULL; + if (!pixbuf) + { + if (err) + *err = local_err; + else + { + g_warning ("Error loading icon from file '%s':\n\t%s", + filename, local_err->message); + g_error_free (local_err); + } + } + + return pixbuf; +} + +/** + * gtk_window_set_icon_from_file: + * @window: a #GtkWindow + * @filename: location of icon file + * @err: location to store error, or %NULL. + * + * Sets the icon for @window. + * Warns on failure if @err is %NULL. + * + * This function is equivalent to calling gtk_window_set_icon() + * with a pixbuf created by loading the image from @filename. + * + * Returns: %TRUE if setting the icon succeeded. + * + * Since: 2.2 + **/ +gboolean +gtk_window_set_icon_from_file (GtkWindow *window, + const gchar *filename, + GError **err) +{ + GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err); + + if (pixbuf) + { + gtk_window_set_icon (window, pixbuf); + g_object_unref (pixbuf); + + return TRUE; + } + else + return FALSE; +} + +/** + * gtk_window_set_default_icon_list: + * @list: a list of #GdkPixbuf + * + * Sets an icon list to be used as fallback for windows that haven't + * had gtk_window_set_icon_list() called on them to set up a + * window-specific icon list. This function allows you to set up the + * icon for all windows in your app at once. + * + * See gtk_window_set_icon_list() for more details. + * + **/ +void +gtk_window_set_default_icon_list (GList *list) +{ + GList *toplevels; + GList *tmp_list; + if (list == default_icon_list) + return; + + /* Update serial so we don't used cached pixmaps/masks + */ + default_icon_serial++; g_list_foreach (default_icon_list, (GFunc) g_object_unref, NULL); @@ -2303,6 +2766,39 @@ gtk_window_set_default_icon_list (GList *list) g_list_free (toplevels); } +/** + * gtk_window_set_default_icon_from_file: + * @filename: location of icon file + * @err: location to store error, or %NULL. + * + * Sets an icon to be used as fallback for windows that haven't + * had gtk_window_set_icon_list() called on them from a file + * on disk. Warns on failure if @err is %NULL. + * + * Returns: %TRUE if setting the icon succeeded. + * + * Since: 2.2 + **/ +gboolean +gtk_window_set_default_icon_from_file (const gchar *filename, + GError **err) +{ + GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err); + + if (pixbuf) + { + GList *list = g_list_prepend (NULL, pixbuf); + gtk_window_set_default_icon_list (list); + g_list_free (list); + + g_object_unref (pixbuf); + + return TRUE; + } + else + return FALSE; +} + /** * gtk_window_get_default_icon_list: * @@ -2324,11 +2820,11 @@ gtk_window_set_default_size_internal (GtkWindow *window, gboolean change_width, gint width, gboolean change_height, - gint height) + gint height, + gboolean is_geometry) { GtkWindowGeometryInfo *info; - g_return_if_fail (GTK_IS_WINDOW (window)); g_return_if_fail (change_width == FALSE || width >= -1); g_return_if_fail (change_height == FALSE || height >= -1); @@ -2336,6 +2832,8 @@ gtk_window_set_default_size_internal (GtkWindow *window, g_object_freeze_notify (G_OBJECT (window)); + info->default_is_geometry = is_geometry != FALSE; + if (change_width) { if (width == 0) @@ -2390,11 +2888,6 @@ gtk_window_set_default_size_internal (GtkWindow *window, * For more control over a window's initial size and how resizing works, * investigate gtk_window_set_geometry_hints(). * - * A useful feature: if you set the "geometry widget" via - * gtk_window_set_geometry_hints(), the default size specified by - * gtk_window_set_default_size() will be the default size of that - * widget, not of the entire window. - * * For some uses, gtk_window_resize() is a more appropriate function. * gtk_window_resize() changes the current size of the window, rather * than the size to be used on initial display. gtk_window_resize() always @@ -2416,7 +2909,7 @@ gtk_window_set_default_size (GtkWindow *window, g_return_if_fail (width >= -1); g_return_if_fail (height >= -1); - gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height); + gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE); } /** @@ -2452,8 +2945,8 @@ gtk_window_get_default_size (GtkWindow *window, /** * gtk_window_resize: * @window: a #GtkWindow - * @width: width to resize the window to - * @height: height to resize the window to + * @width: width in pixels to resize the window to + * @height: height in pixels to resize the window to * * Resizes the window as if the user had done so, obeying geometry * constraints. The default geometry constraint is that windows may @@ -2494,9 +2987,10 @@ gtk_window_resize (GtkWindow *window, * @height: return location for height, or %NULL * * Obtains the current size of @window. If @window is not onscreen, - * it returns the size GTK+ will suggest to the window manager for the - * initial window size (but this is not reliably the same as the size - * the window manager will actually select). The size obtained by + * it returns the size GTK+ will suggest to the window manager for the initial window + * size (but this is not reliably the same as the size the window + * manager will actually select). The size obtained by * gtk_window_get_size() is the last size received in a * #GdkEventConfigure, that is, GTK+ uses its locally-stored size, * rather than querying the X server for the size. As a result, if you @@ -2513,10 +3007,10 @@ gtk_window_resize (GtkWindow *window, * "configure_event" on the window and adjust your size-dependent * state to match the size delivered in the #GdkEventConfigure. * - * Note 2: The returned size does not include the size of the window - * manager decorations (aka the window frame or border). Those - * are not drawn by GTK+ and GTK+ has no reliable method of - * determining their size. + * Note 2: The returned size does not include the + * size of the window manager decorations (aka the window frame or + * border). Those are not drawn by GTK+ and GTK+ has no reliable + * method of determining their size. * * Note 3: If you are getting a window size in order to position * the window onscreen, there may be a better way. The preferred @@ -2533,9 +3027,9 @@ gtk_window_resize (GtkWindow *window, * application cannot. * * In any case, if you insist on application-specified window - * positioning, there's still a better way than doing it yourself - - * gtk_window_set_position() will frequently handle the details - * for you. + * positioning, there's still a better way than + * doing it yourself - gtk_window_set_position() will frequently + * handle the details for you. * **/ void @@ -2582,11 +3076,11 @@ gtk_window_get_size (GtkWindow *window, * @x: X coordinate to move window to * @y: Y coordinate to move window to * - * Asks the window manager to move @window to the given position. - * Window managers are free to ignore this; most window managers - * ignore requests for initial window positions (instead using a - * user-defined placement algorithm) and honor requests after the - * window has already been shown. + * Asks the window manager to move + * @window to the given position. Window managers are free to ignore + * this; most window managers ignore requests for initial window + * positions (instead using a user-defined placement algorithm) and + * honor requests after the window has already been shown. * * Note: the position is the position of the gravity-determined * reference point for the window. The gravity determines two things: @@ -2611,8 +3105,8 @@ gtk_window_get_size (GtkWindow *window, * gdk_screen_height () - window_height). * * The extended window manager hints specification at http://www.freedesktop.org/standards/wm-spec.html has a + * url="http://www.freedesktop.org/standards/wm-spec.html"> + * http://www.freedesktop.org/standards/wm-spec.html has a * nice table of gravities in the "implementation notes" section. * * The gtk_window_get_position() documentation may also be relevant. @@ -2704,10 +3198,11 @@ gtk_window_move (GtkWindow *window, * Thus GTK+ is using a "best guess" that works with most * window managers. * - * Moreover, nearly all window managers are broken with respect to - * their handling of window gravity. So moving a window to its current - * position as returned by gtk_window_get_position() tends to - * result in moving the window slightly. + * Moreover, nearly all window managers are historically broken with + * respect to their handling of window gravity. So moving a window to + * its current position as returned by gtk_window_get_position() tends + * to result in moving the window slightly. Window managers are + * slowly getting better over time. * * If a window has gravity #GDK_GRAVITY_STATIC the window manager * frame is not relevant, and thus gtk_window_get_position() will @@ -2869,11 +3364,7 @@ gtk_window_reshow_with_initial_size (GtkWindow *window) static void gtk_window_destroy (GtkObject *object) { - GtkWindow *window; - - g_return_if_fail (GTK_IS_WINDOW (object)); - - window = GTK_WINDOW (object); + GtkWindow *window = GTK_WINDOW (object); if (window->transient_parent) gtk_window_set_transient_for (window, NULL); @@ -2884,13 +3375,15 @@ gtk_window_destroy (GtkObject *object) if (window->has_user_ref_count) { window->has_user_ref_count = FALSE; - gtk_widget_unref (GTK_WIDGET (window)); + g_object_unref (window); } if (window->group) gtk_window_group_remove_window (window->group, window); - GTK_OBJECT_CLASS (parent_class)->destroy (object); + gtk_window_free_key_hash (window); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); } static gboolean @@ -2920,13 +3413,16 @@ gtk_window_mnemonic_hash_remove (gpointer key, } static void -gtk_window_finalize (GObject *object) +gtk_window_private_finalize (GtkWindowPrivate *priv) { - GtkWindow *window; - - g_return_if_fail (GTK_IS_WINDOW (object)); + + g_free (priv); +} - window = GTK_WINDOW (object); +static void +gtk_window_finalize (GObject *object) +{ + GtkWindow *window = GTK_WINDOW (object); toplevel_list = g_slist_remove (toplevel_list, window); @@ -2941,9 +3437,9 @@ gtk_window_finalize (GObject *object) if (window->geometry_info) { if (window->geometry_info->widget) - gtk_signal_disconnect_by_func (GTK_OBJECT (window->geometry_info->widget), - GTK_SIGNAL_FUNC (gtk_widget_destroyed), - &window->geometry_info->widget); + g_signal_handlers_disconnect_by_func (window->geometry_info->widget, + gtk_widget_destroyed, + &window->geometry_info->widget); g_free (window->geometry_info); } @@ -2962,12 +3458,12 @@ gtk_window_show (GtkWidget *widget) GtkWindow *window = GTK_WINDOW (widget); GtkContainer *container = GTK_CONTAINER (window); gboolean need_resize; - + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget); container->need_resize = FALSE; - + if (need_resize) { GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE); @@ -3028,6 +3524,15 @@ gtk_window_show (GtkWidget *widget) gtk_widget_map (widget); + /* Try to make sure that we have some focused widget + */ +#ifdef GDK_WINDOWING_X11 + if (!window->focus_widget && !GTK_IS_PLUG (window)) +#else + if (!window->focus_widget) +#endif + gtk_window_move_focus (window, GTK_DIR_TAB_FORWARD); + if (window->modal) gtk_grab_add (widget); } @@ -3035,11 +3540,7 @@ gtk_window_show (GtkWidget *widget) static void gtk_window_hide (GtkWidget *widget) { - GtkWindow *window; - - g_return_if_fail (GTK_IS_WINDOW (widget)); - - window = GTK_WINDOW (widget); + GtkWindow *window = GTK_WINDOW (widget); GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); gtk_widget_unmap (widget); @@ -3051,15 +3552,14 @@ gtk_window_hide (GtkWidget *widget) static void gtk_window_map (GtkWidget *widget) { - GtkWindow *window; + GtkWindow *window = GTK_WINDOW (widget); GdkWindow *toplevel; - - g_return_if_fail (GTK_IS_WINDOW (widget)); + GtkWindowPrivate *priv; + priv = gtk_window_get_private (window); + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - window = GTK_WINDOW (widget); - if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child) && !GTK_WIDGET_MAPPED (window->bin.child)) @@ -3085,6 +3585,11 @@ gtk_window_map (GtkWidget *widget) else gdk_window_deiconify (toplevel); + if (priv->fullscreen_initially) + gdk_window_fullscreen (toplevel); + else + gdk_window_unfullscreen (toplevel); + /* No longer use the default settings */ window->need_default_size = FALSE; window->need_default_position = FALSE; @@ -3093,16 +3598,22 @@ gtk_window_map (GtkWidget *widget) if (window->frame) gdk_window_show (window->frame); + + if (!disable_startup_notification && + !sent_startup_notification) + { + sent_startup_notification = TRUE; + gdk_notify_startup_complete (); + } } static void gtk_window_unmap (GtkWidget *widget) { - GtkWindow *window; + GtkWindow *window = GTK_WINDOW (widget); GtkWindowGeometryInfo *info; + GdkWindowState state; - window = GTK_WINDOW (widget); - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); if (window->frame) gdk_window_withdraw (window->frame); @@ -3124,6 +3635,11 @@ gtk_window_unmap (GtkWidget *widget) info->initial_pos_set = FALSE; info->position_constraints_changed = FALSE; } + + state = gdk_window_get_state (widget->window); + window->iconify_initially = state & GDK_WINDOW_STATE_ICONIFIED; + window->maximize_initially = state & GDK_WINDOW_STATE_MAXIMIZED; + window->stick_initially = state & GDK_WINDOW_STATE_STICKY; } static void @@ -3134,8 +3650,6 @@ gtk_window_realize (GtkWidget *widget) GdkWindowAttr attributes; gint attributes_mask; - g_return_if_fail (GTK_IS_WINDOW (widget)); - window = GTK_WINDOW (widget); /* ensure widget tree is properly size allocated */ @@ -3200,12 +3714,14 @@ gtk_window_realize (GtkWidget *widget) attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; - window->frame = gdk_window_new (NULL, &attributes, attributes_mask); + window->frame = gdk_window_new (gtk_widget_get_root_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (window->frame, widget); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = window->frame_left; - attributes.y = window->frame_right; + attributes.y = window->frame_top; attributes_mask = GDK_WA_X | GDK_WA_Y; @@ -3214,7 +3730,7 @@ gtk_window_realize (GtkWidget *widget) else { attributes_mask = 0; - parent_window = NULL; + parent_window = gtk_widget_get_root_window (widget); } attributes.width = widget->allocation.width; @@ -3231,7 +3747,9 @@ gtk_window_realize (GtkWidget *widget) attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP; attributes_mask |= (window->title ? GDK_WA_TITLE : 0); attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); + widget->window = gdk_window_new (parent_window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, window); widget->style = gtk_style_attach (widget->style, widget->window); @@ -3255,8 +3773,13 @@ gtk_window_realize (GtkWidget *widget) gdk_window_set_type_hint (widget->window, window->type_hint); - /* transient_for must be set to allow the modal hint */ - if (window->transient_parent && window->modal) + if (gtk_window_get_skip_pager_hint (window)) + gdk_window_set_skip_pager_hint (widget->window, TRUE); + + if (gtk_window_get_skip_taskbar_hint (window)) + gdk_window_set_skip_taskbar_hint (widget->window, TRUE); + + if (window->modal) gdk_window_set_modal_hint (widget->window, TRUE); else gdk_window_set_modal_hint (widget->window, FALSE); @@ -3313,9 +3836,6 @@ gtk_window_size_request (GtkWidget *widget, GtkWindow *window; GtkBin *bin; - g_return_if_fail (GTK_IS_WINDOW (widget)); - g_return_if_fail (requisition != NULL); - window = GTK_WINDOW (widget); bin = GTK_BIN (window); @@ -3340,9 +3860,6 @@ gtk_window_size_allocate (GtkWidget *widget, GtkWindow *window; GtkAllocation child_allocation; - g_return_if_fail (GTK_IS_WINDOW (widget)); - g_return_if_fail (allocation != NULL); - window = GTK_WINDOW (widget); widget->allocation = *allocation; @@ -3372,10 +3889,6 @@ gtk_window_event (GtkWidget *widget, GdkEvent *event) GtkWindow *window; gboolean return_val; - - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - window = GTK_WINDOW (widget); if (window->frame && (event->any.window == window->frame)) @@ -3384,9 +3897,9 @@ gtk_window_event (GtkWidget *widget, GdkEvent *event) (event->type != GDK_KEY_RELEASE) && (event->type != GDK_FOCUS_CHANGE)) { - gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event"); + g_signal_stop_emission_by_name (widget, "event"); return_val = FALSE; - gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val); + g_signal_emit (widget, window_signals[FRAME_EVENT], 0, event, &return_val); return TRUE; } else @@ -3433,12 +3946,8 @@ static gint gtk_window_configure_event (GtkWidget *widget, GdkEventConfigure *event) { - GtkWindow *window; - - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - window = GTK_WINDOW (widget); + GtkWindow *window = GTK_WINDOW (widget); + gboolean expected_reply = window->configure_request_count > 0; /* window->configure_request_count incremented for each * configure request, and decremented to a min of 0 for @@ -3463,7 +3972,7 @@ gtk_window_configure_event (GtkWidget *widget, * notifies and can wait to resize when we get them */ - if (window->configure_request_count > 0 || + if (!expected_reply && (widget->allocation.width == event->width && widget->allocation.height == event->height)) return TRUE; @@ -3536,20 +4045,14 @@ gtk_window_key_press_event (GtkWidget *widget, GtkWidget *focus; gboolean handled; - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - window = GTK_WINDOW (widget); handled = FALSE; + /* Check for mnemonics and accelerators + */ if (!handled) - handled = gtk_window_mnemonic_activate (window, - event->keyval, - event->state); - - if (!handled) - handled = gtk_accel_groups_activate (G_OBJECT (window), event->keyval, event->state); + handled = _gtk_window_activate_key (window, event); if (!handled) { @@ -3593,9 +4096,6 @@ gtk_window_key_release_event (GtkWidget *widget, GtkWindow *window; gint handled; - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - window = GTK_WINDOW (widget); handled = FALSE; if (window->focus_widget && @@ -3637,9 +4137,6 @@ static gint gtk_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) { - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - return FALSE; } @@ -3647,18 +4144,41 @@ static gint gtk_window_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) { - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - return FALSE; } +static void +do_focus_change (GtkWidget *widget, + gboolean in) +{ + GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE); + + g_object_ref (widget); + + if (in) + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + else + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + + fevent->focus_change.type = GDK_FOCUS_CHANGE; + fevent->focus_change.window = widget->window; + if (widget->window) + g_object_ref (widget->window); + fevent->focus_change.in = in; + + gtk_widget_event (widget, fevent); + + g_object_notify (G_OBJECT (widget), "has_focus"); + + g_object_unref (widget); + gdk_event_free (fevent); +} + static gint gtk_window_focus_in_event (GtkWidget *widget, GdkEventFocus *event) { GtkWindow *window = GTK_WINDOW (widget); - GdkEventFocus fevent; /* It appears spurious focus in events can occur when * the window is hidden. So we'll just check to see if @@ -3667,20 +4187,10 @@ gtk_window_focus_in_event (GtkWidget *widget, */ if (GTK_WIDGET_VISIBLE (widget)) { - window->has_focus = TRUE; - - if (window->focus_widget && - window->focus_widget != widget && - !GTK_WIDGET_HAS_FOCUS (window->focus_widget)) - { - fevent.type = GDK_FOCUS_CHANGE; - fevent.window = window->focus_widget->window; - fevent.in = TRUE; - - gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent); - } + _gtk_window_set_has_toplevel_focus (window, TRUE); + _gtk_window_set_is_active (window, TRUE); } - + return FALSE; } @@ -3689,20 +4199,9 @@ gtk_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event) { GtkWindow *window = GTK_WINDOW (widget); - GdkEventFocus fevent; - window->has_focus = FALSE; - - if (window->focus_widget && - window->focus_widget != widget && - GTK_WIDGET_HAS_FOCUS (window->focus_widget)) - { - fevent.type = GDK_FOCUS_CHANGE; - fevent.window = window->focus_widget->window; - fevent.in = FALSE; - - gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent); - } + _gtk_window_set_has_toplevel_focus (window, FALSE); + _gtk_window_set_is_active (window, FALSE); return FALSE; } @@ -3715,35 +4214,34 @@ gtk_window_read_rcfiles (GtkWidget *widget, { GList *embedded_windows; - embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded"); + embedded_windows = g_object_get_data (G_OBJECT (widget), "gtk-embedded"); if (embedded_windows) { - GdkEventClient sev; + GdkEvent *send_event = gdk_event_new (GDK_CLIENT_EVENT); int i; for (i = 0; i < 5; i++) - sev.data.l[i] = 0; - sev.data_format = 32; - sev.message_type = atom_rcfiles; + send_event->client.data.l[i] = 0; + send_event->client.data_format = 32; + send_event->client.message_type = atom_rcfiles; while (embedded_windows) { guint xid = GPOINTER_TO_UINT (embedded_windows->data); - gdk_event_send_client_message ((GdkEvent *) &sev, xid); + gdk_event_send_client_message_for_display (gtk_widget_get_display (widget), send_event, xid); embedded_windows = embedded_windows->next; } + + gdk_event_free (send_event); } - gtk_rc_reparse_all (); + gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), FALSE); } static gint gtk_window_client_event (GtkWidget *widget, GdkEventClient *event) { - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - if (!atom_rcfiles) atom_rcfiles = gdk_atom_intern ("_GTK_READ_RCFILES", FALSE); @@ -3756,11 +4254,7 @@ gtk_window_client_event (GtkWidget *widget, static void gtk_window_check_resize (GtkContainer *container) { - GtkWindow *window; - - g_return_if_fail (GTK_IS_WINDOW (container)); - - window = GTK_WINDOW (container); + GtkWindow *window = GTK_WINDOW (container); if (GTK_WIDGET_VISIBLE (container)) gtk_window_move_resize (window); @@ -3819,10 +4313,19 @@ static void gtk_window_real_set_focus (GtkWindow *window, GtkWidget *focus) { - GdkEventFocus event; + GtkWidget *old_focus = window->focus_widget; gboolean def_flags = 0; - g_return_if_fail (GTK_IS_WINDOW (window)); + if (old_focus) + { + g_object_ref (old_focus); + g_object_freeze_notify (G_OBJECT (old_focus)); + } + if (focus) + { + g_object_ref (focus); + g_object_freeze_notify (G_OBJECT (focus)); + } if (window->default_widget) def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget); @@ -3839,13 +4342,9 @@ gtk_window_real_set_focus (GtkWindow *window, } if (window->has_focus) - { - event.type = GDK_FOCUS_CHANGE; - event.window = window->focus_widget->window; - event.in = FALSE; - - gtk_widget_event (window->focus_widget, (GdkEvent*) &event); - } + do_focus_change (window->focus_widget, FALSE); + + g_object_notify (G_OBJECT (window->focus_widget), "is_focus"); } window->focus_widget = focus; @@ -3863,18 +4362,60 @@ gtk_window_real_set_focus (GtkWindow *window, } if (window->has_focus) - { - event.type = GDK_FOCUS_CHANGE; - event.window = window->focus_widget->window; - event.in = TRUE; - - gtk_widget_event (window->focus_widget, (GdkEvent*) &event); - } + do_focus_change (window->focus_widget, TRUE); + + g_object_notify (G_OBJECT (window->focus_widget), "is_focus"); } if (window->default_widget && (def_flags != GTK_WIDGET_FLAGS (window->default_widget))) gtk_widget_queue_draw (window->default_widget); + + if (old_focus) + { + g_object_thaw_notify (G_OBJECT (old_focus)); + g_object_unref (old_focus); + } + if (focus) + { + g_object_thaw_notify (G_OBJECT (focus)); + g_object_unref (focus); + } +} + +/** + * _gtk_window_unset_focus_and_default: + * @window: a #GtkWindow + * @widget: a widget inside of @window + * + * Checks whether the focus and default widgets of @window are + * @widget or a descendent of @widget, and if so, unset them. + **/ +void +_gtk_window_unset_focus_and_default (GtkWindow *window, + GtkWidget *widget) + +{ + GtkWidget *child; + + if (GTK_CONTAINER (widget->parent)->focus_child == widget) + { + child = window->focus_widget; + + while (child && child != widget) + child = child->parent; + + if (child == widget) + gtk_window_set_focus (GTK_WINDOW (window), NULL); + } + + child = window->default_widget; + + while (child && child != widget) + child = child->parent; + + if (child == widget) + gtk_window_set_default (window, NULL); } /********************************* @@ -3918,11 +4459,41 @@ gtk_window_compute_configure_request_size (GtkWindow *window, if (info) { - if (info->default_width > 0) - *width = info->default_width; - - if (info->default_height > 0) - *height = info->default_height; + gint base_width = 0; + gint base_height = 0; + gint width_inc = 1; + gint height_inc = 1; + + if (info->default_is_geometry && + (info->default_width > 0 || info->default_height > 0)) + { + GdkGeometry geometry; + guint flags; + + gtk_window_compute_hints (window, &geometry, &flags); + + if (flags & GDK_HINT_BASE_SIZE) + { + base_width = geometry.base_width; + base_height = geometry.base_height; + } + else if (flags & GDK_HINT_MIN_SIZE) + { + base_width = geometry.min_width; + base_height = geometry.min_height; + } + if (flags & GDK_HINT_RESIZE_INC) + { + width_inc = geometry.width_inc; + height_inc = geometry.height_inc; + } + } + + if (info->default_width > 0) + *width = info->default_width * width_inc + base_width; + + if (info->default_height > 0) + *height = info->default_height * height_inc + base_height; } } else @@ -3943,6 +4514,104 @@ gtk_window_compute_configure_request_size (GtkWindow *window, } } +static GtkWindowPosition +get_effective_position (GtkWindow *window) +{ + GtkWindowPosition pos = window->position; + if (pos == GTK_WIN_POS_CENTER_ON_PARENT && + (window->transient_parent == NULL || + !GTK_WIDGET_MAPPED (window->transient_parent))) + pos = GTK_WIN_POS_NONE; + + return pos; +} + +static int +get_center_monitor_of_window (GtkWindow *window) +{ + /* We could try to sort out the relative positions of the monitors and + * stuff, or we could just be losers and assume you have a row + * or column of monitors. + */ + return gdk_screen_get_n_monitors (gtk_window_check_screen (window)) / 2; +} + +static int +get_monitor_containing_pointer (GtkWindow *window) +{ + gint px, py; + gint monitor_num; + GdkScreen *window_screen; + GdkScreen *pointer_screen; + + window_screen = gtk_window_check_screen (window); + gdk_display_get_pointer (gdk_screen_get_display (window_screen), + &pointer_screen, + &px, &py, NULL); + + if (pointer_screen == window_screen) + monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py); + else + monitor_num = -1; + + return monitor_num; +} + +static void +center_window_on_monitor (GtkWindow *window, + gint w, + gint h, + gint *x, + gint *y) +{ + GdkRectangle monitor; + int monitor_num; + + monitor_num = get_monitor_containing_pointer (window); + + if (monitor_num == -1) + monitor_num = get_center_monitor_of_window (window); + + gdk_screen_get_monitor_geometry (gtk_window_check_screen (window), + monitor_num, &monitor); + + *x = (monitor.width - w) / 2 + monitor.x; + *y = (monitor.height - h) / 2 + monitor.y; + + /* Be sure we aren't off the monitor, ignoring _NET_WM_STRUT + * and WM decorations. + */ + if (*x < monitor.x) + *x = monitor.x; + if (*y < monitor.y) + *y = monitor.y; +} + +static void +clamp_window_to_rectangle (gint *x, + gint *y, + gint w, + gint h, + const GdkRectangle *rect) +{ + gint outside_w, outside_h; + + outside_w = (*x + w) - (rect->x + rect->width); + if (outside_w > 0) + *x -= outside_w; + + outside_h = (*y + h) - (rect->y + rect->height); + if (outside_h > 0) + *y -= outside_h; + + /* if larger than the screen, center on the screen. */ + if (*x < rect->x) + *x += (rect->x - *x) / 2; + if (*y < rect->y) + *y += (rect->y - *y) / 2; +} + + static void gtk_window_compute_configure_request (GtkWindow *window, GdkRectangle *request, @@ -3956,9 +4625,12 @@ gtk_window_compute_configure_request (GtkWindow *window, GtkWindowPosition pos; GtkWidget *parent_widget; GtkWindowGeometryInfo *info; + GdkScreen *screen; int x, y; widget = GTK_WIDGET (window); + + screen = gtk_window_check_screen (window); gtk_widget_size_request (widget, NULL); gtk_window_compute_configure_request_size (window, &w, &h); @@ -3971,12 +4643,7 @@ gtk_window_compute_configure_request (GtkWindow *window, parent_widget = (GtkWidget*) window->transient_parent; - pos = window->position; - if (pos == GTK_WIN_POS_CENTER_ON_PARENT && - (parent_widget == NULL || - !GTK_WIDGET_MAPPED (parent_widget))) - pos = GTK_WIN_POS_NONE; - + pos = get_effective_position (window); info = gtk_window_get_geometry_info (window, TRUE); /* by default, don't change position requested */ @@ -4000,40 +4667,73 @@ gtk_window_compute_configure_request (GtkWindow *window, */ case GTK_WIN_POS_CENTER_ALWAYS: case GTK_WIN_POS_CENTER: - { - gint screen_width = gdk_screen_width (); - gint screen_height = gdk_screen_height (); - - x = (screen_width - w) / 2; - y = (screen_height - h) / 2; - } + center_window_on_monitor (window, w, h, &x, &y); break; case GTK_WIN_POS_CENTER_ON_PARENT: { + gint monitor_num; + GdkRectangle monitor; gint ox, oy; g_assert (GTK_WIDGET_MAPPED (parent_widget)); /* established earlier */ + + if (parent_widget->window != NULL) + monitor_num = gdk_screen_get_monitor_at_window (screen, + parent_widget->window); + else + monitor_num = -1; gdk_window_get_origin (parent_widget->window, &ox, &oy); x = ox + (parent_widget->allocation.width - w) / 2; y = oy + (parent_widget->allocation.height - h) / 2; + + /* Clamp onto current monitor, ignoring _NET_WM_STRUT and + * WM decorations. If parent wasn't on a monitor, just + * give up. + */ + if (monitor_num >= 0) + { + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + clamp_window_to_rectangle (&x, &y, w, h, &monitor); + } } break; case GTK_WIN_POS_MOUSE: { - gint screen_width = gdk_screen_width (); - gint screen_height = gdk_screen_height (); - int px, py; + gint screen_width = gdk_screen_get_width (screen); + gint screen_height = gdk_screen_get_height (screen); + gint monitor_num; + GdkRectangle monitor; + GdkScreen *pointer_screen; + gint px, py; + + gdk_display_get_pointer (gdk_screen_get_display (screen), + &pointer_screen, + &px, &py, NULL); + + if (pointer_screen == screen) + monitor_num = gdk_screen_get_monitor_at_point (screen, px, py); + else + monitor_num = -1; - gdk_window_get_pointer (NULL, &px, &py, NULL); x = px - w / 2; y = py - h / 2; x = CLAMP (x, 0, screen_width - w); y = CLAMP (y, 0, screen_height - h); + + /* Clamp onto current monitor, ignoring _NET_WM_STRUT and + * WM decorations. Don't try to figure out what's going + * on if the mouse wasn't inside a monitor. + */ + if (monitor_num >= 0) + { + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + clamp_window_to_rectangle (&x, &y, w, h, &monitor); + } } break; @@ -4074,11 +4774,8 @@ gtk_window_constrain_position (GtkWindow *window, if (window->position == GTK_WIN_POS_CENTER_ALWAYS) { gint center_x, center_y; - gint screen_width = gdk_screen_width (); - gint screen_height = gdk_screen_height (); - - center_x = (screen_width - new_width) / 2; - center_y = (screen_height - new_height) / 2; + + center_window_on_monitor (window, new_width, new_height, ¢er_x, ¢er_y); *x = center_x; *y = center_y; @@ -4228,42 +4925,46 @@ gtk_window_move_resize (GtkWindow *window) } #if 0 - { - int notify_x, notify_y; + if (window->type == GTK_WINDOW_TOPLEVEL) + { + int notify_x, notify_y; - /* this is the position from the last configure notify */ - gdk_window_get_position (widget->window, ¬ify_x, ¬ify_y); + /* this is the position from the last configure notify */ + gdk_window_get_position (widget->window, ¬ify_x, ¬ify_y); - g_print ("--- %s ---\n" - "last : %d,%d\t%d x %d\n" - "this : %d,%d\t%d x %d\n" - "alloc: %d,%d\t%d x %d\n" - "req : \t%d x %d\n" - "size_changed: %d pos_changed: %d hints_changed: %d\n" - "configure_notify_received: %d\n" - "configure_request_count: %d\n" - "position_constraints_changed: %d\n", - window->title ? window->title : "(no title)", - info->last.configure_request.x, - info->last.configure_request.y, - info->last.configure_request.width, - info->last.configure_request.height, - new_request.x, - new_request.y, - new_request.width, - new_request.height, - notify_x, notify_y, - widget->allocation.width, - widget->allocation.height, - widget->requisition.width, - widget->requisition.height, - configure_request_pos_changed, - configure_request_size_changed, - hints_changed, - window->configure_notify_received, - window->configure_request_count, - info->position_constraints_changed); - } + g_message ("--- %s ---\n" + "last : %d,%d\t%d x %d\n" + "this : %d,%d\t%d x %d\n" + "alloc : %d,%d\t%d x %d\n" + "req : \t%d x %d\n" + "resize: \t%d x %d\n" + "size_changed: %d pos_changed: %d hints_changed: %d\n" + "configure_notify_received: %d\n" + "configure_request_count: %d\n" + "position_constraints_changed: %d\n", + window->title ? window->title : "(no title)", + info->last.configure_request.x, + info->last.configure_request.y, + info->last.configure_request.width, + info->last.configure_request.height, + new_request.x, + new_request.y, + new_request.width, + new_request.height, + notify_x, notify_y, + widget->allocation.width, + widget->allocation.height, + widget->requisition.width, + widget->requisition.height, + info->resize_width, + info->resize_height, + configure_request_pos_changed, + configure_request_size_changed, + hints_changed, + window->configure_notify_received, + window->configure_request_count, + info->position_constraints_changed); + } #endif saved_last_info = info->last; @@ -4289,7 +4990,7 @@ gtk_window_move_resize (GtkWindow *window) if ((configure_request_pos_changed || info->initial_pos_set || (window->need_default_position && - window->position != GTK_WIN_POS_NONE)) && + get_effective_position (window) != GTK_WIN_POS_NONE)) && (new_flags & GDK_HINT_POS) == 0) { new_flags |= GDK_HINT_POS; @@ -4302,7 +5003,7 @@ gtk_window_move_resize (GtkWindow *window) gdk_window_set_geometry_hints (widget->window, &new_geometry, new_flags); - + /* handle resizing/moving and widget tree allocation */ if (window->configure_notify_received) @@ -4364,6 +5065,8 @@ gtk_window_move_resize (GtkWindow *window) gtk_widget_queue_resize (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */ } + + return; /* Bail out, we didn't really process the move/resize */ } else if ((configure_request_size_changed || hints_changed) && (widget->allocation.width != new_request.width || @@ -4395,13 +5098,13 @@ gtk_window_move_resize (GtkWindow *window) new_request.y - window->frame_top, new_request.width + window->frame_left + window->frame_right, new_request.height + window->frame_top + window->frame_bottom); - gdk_window_resize (GTK_WIDGET (window)->window, + gdk_window_resize (widget->window, new_request.width, new_request.height); } else gdk_window_move_resize (widget->window, - new_request.x, new_request.y, - new_request.width, new_request.height); + new_request.x, new_request.y, + new_request.width, new_request.height); } else /* only size changed */ { @@ -4410,21 +5113,12 @@ gtk_window_move_resize (GtkWindow *window) new_request.width + window->frame_left + window->frame_right, new_request.height + window->frame_top + window->frame_bottom); gdk_window_resize (widget->window, - new_request.width, new_request.height); + new_request.width, new_request.height); } /* Increment the number of have-not-yet-received-notify requests */ window->configure_request_count += 1; - /* We have now sent a request since the last position constraint - * change and definitely don't need a an initial size again (not - * resetting this here can lead to infinite loops for - * GTK_RESIZE_IMMEDIATE containers) - */ - info->position_constraints_changed = FALSE; - window->need_default_position = FALSE; - info->initial_pos_set = FALSE; - /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new * configure event in response to our resizing request. * the configure event will cause a new resize with @@ -4462,11 +5156,21 @@ gtk_window_move_resize (GtkWindow *window) gdk_window_move (widget->window, new_request.x, new_request.y); } - + /* And run the resize queue. */ gtk_container_resize_children (container); } + + /* We have now processed a move/resize since the last position + * constraint change, setting of the initial position, or resize. + * (Not resetting these flags here can lead to infinite loops for + * GTK_RESIZE_IMMEDIATE containers) + */ + info->position_constraints_changed = FALSE; + info->initial_pos_set = FALSE; + info->resize_width = -1; + info->resize_height = -1; } /* Compare two sets of Geometry hints for equality. @@ -4568,8 +5272,6 @@ gtk_window_compute_hints (GtkWindow *window, GtkWindowGeometryInfo *geometry_info; GtkRequisition requisition; - g_return_if_fail (GTK_IS_WINDOW (window)); - widget = GTK_WIDGET (window); gtk_widget_get_child_requisition (widget, &requisition); @@ -4687,9 +5389,6 @@ static gint gtk_window_expose (GtkWidget *widget, GdkEventExpose *event) { - g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - if (!GTK_WIDGET_APP_PAINTABLE (widget)) gtk_window_paint (widget, &event->area); @@ -4770,10 +5469,12 @@ gtk_window_set_frame_dimensions (GtkWindow *window, gint right, gint bottom) { - GtkWidget *widget = GTK_WIDGET (window); + GtkWidget *widget; g_return_if_fail (GTK_IS_WINDOW (window)); + widget = GTK_WIDGET (window); + if (window->frame_left == left && window->frame_top == top && window->frame_right == right && @@ -4847,12 +5548,13 @@ gtk_window_present (GtkWindow *window) * gtk_window_iconify: * @window: a #GtkWindow * - * Asks to iconify (i.e. minimize) the specified @window. Note that you - * shouldn't assume the window is definitely iconified afterward, - * because other entities (e.g. the user or window manager) could - * deiconify it again, or there may not be a window manager in which - * case iconification isn't possible, etc. But normally the window - * will end up iconified. Just don't write code that crashes if not. + * Asks to iconify (i.e. minimize) the specified @window. Note that + * you shouldn't assume the window is definitely iconified afterward, + * because other entities (e.g. the user or window manager) could deiconify it + * again, or there may not be a window manager in which case + * iconification isn't possible, etc. But normally the window will end + * up iconified. Just don't write code that crashes if not. * * It's permitted to call this function before showing a window, * in which case the window will be iconified before it ever appears @@ -4889,9 +5591,9 @@ gtk_window_iconify (GtkWindow *window) * * Asks to deiconify (i.e. unminimize) the specified @window. Note * that you shouldn't assume the window is definitely deiconified - * afterward, because other entities (e.g. the user or window manager) - * could iconify it again before your code which assumes - * deiconification gets to run. + * afterward, because other entities (e.g. the user or window manager) could iconify it + * again before your code which assumes deiconification gets to run. * * You can track iconification via the "window_state_event" signal * on #GtkWidget. @@ -4923,10 +5625,11 @@ gtk_window_deiconify (GtkWindow *window) * * Asks to stick @window, which means that it will appear on all user * desktops. Note that you shouldn't assume the window is definitely - * stuck afterward, because other entities (e.g. the user or window - * manager) could unstick it again, and some window managers do not - * support sticking windows. But normally the window will end up - * stuck. Just don't write code that crashes if not. + * stuck afterward, because other entities (e.g. the user or window manager) could unstick it + * again, and some window managers do not support sticking + * windows. But normally the window will end up stuck. Just don't + * write code that crashes if not. * * It's permitted to call this function before showing a window. * @@ -4962,9 +5665,9 @@ gtk_window_stick (GtkWindow *window) * Asks to unstick @window, which means that it will appear on only * one of the user's desktops. Note that you shouldn't assume the * window is definitely unstuck afterward, because other entities - * (e.g. the user or window manager) could stick it again. But - * normally the window will end up stuck. Just don't write code that - * crashes if not. + * (e.g. the user or window + * manager) could stick it again. But normally the window will + * end up stuck. Just don't write code that crashes if not. * * You can track stickiness via the "window_state_event" signal * on #GtkWidget. @@ -4997,10 +5700,11 @@ gtk_window_unstick (GtkWindow *window) * * Asks to maximize @window, so that it becomes full-screen. Note that * you shouldn't assume the window is definitely maximized afterward, - * because other entities (e.g. the user or window manager) could - * unmaximize it again, and not all window managers support - * maximization. But normally the window will end up maximized. Just - * don't write code that crashes if not. + * because other entities (e.g. the user or window manager) could unmaximize it + * again, and not all window managers support maximization. But + * normally the window will end up maximized. Just don't write code + * that crashes if not. * * It's permitted to call this function before showing a window, * in which case the window will be maximized when it appears onscreen @@ -5037,10 +5741,10 @@ gtk_window_maximize (GtkWindow *window) * * Asks to unmaximize @window. Note that you shouldn't assume the * window is definitely unmaximized afterward, because other entities - * (e.g. the user or window manager) could maximize it again, and not - * all window managers honor requests to unmaximize. But normally the - * window will end up unmaximized. Just don't write code that crashes - * if not. + * (e.g. the user or window + * manager) could maximize it again, and not all window + * managers honor requests to unmaximize. But normally the window will + * end up unmaximized. Just don't write code that crashes if not. * * You can track maximization via the "window_state_event" signal * on #GtkWidget. @@ -5067,6 +5771,87 @@ gtk_window_unmaximize (GtkWindow *window) gdk_window_unmaximize (toplevel); } +/** + * gtk_window_fullscreen: + * @window: a #GtkWindow + * + * Asks to place @window in the fullscreen state. Note that you + * shouldn't assume the window is definitely full screen afterward, + * because other entities (e.g. the user or window manager) could unfullscreen it + * again, and not all window managers honor requests to fullscreen + * windows. But normally the window will end up fullscreen. Just + * don't write code that crashes if not. + * + * You can track the fullscreen state via the "window_state_event" signal + * on #GtkWidget. + * + * Since: 2.2 + **/ +void +gtk_window_fullscreen (GtkWindow *window) +{ + GtkWidget *widget; + GdkWindow *toplevel; + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + widget = GTK_WIDGET (window); + priv = gtk_window_get_private (window); + + priv->fullscreen_initially = TRUE; + + if (window->frame) + toplevel = window->frame; + else + toplevel = widget->window; + + if (toplevel != NULL) + gdk_window_fullscreen (toplevel); +} + +/** + * gtk_window_unfullscreen: + * @window: a #GtkWindow + * + * Asks to toggle off the fullscreen state for @window. Note that you + * shouldn't assume the window is definitely not full screen + * afterward, because other entities (e.g. the user or window manager) could fullscreen it + * again, and not all window managers honor requests to unfullscreen + * windows. But normally the window will end up restored to its normal + * state. Just don't write code that crashes if not. + * + * You can track the fullscreen state via the "window_state_event" signal + * on #GtkWidget. + * + * Since: 2.2 + **/ +void +gtk_window_unfullscreen (GtkWindow *window) +{ + GtkWidget *widget; + GdkWindow *toplevel; + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + widget = GTK_WIDGET (window); + priv = gtk_window_get_private (window); + + priv->fullscreen_initially = FALSE; + + if (window->frame) + toplevel = window->frame; + else + toplevel = widget->window; + + if (toplevel != NULL) + gdk_window_unfullscreen (toplevel); +} + + /** * gtk_window_set_resizable: * @window: a #GtkWindow @@ -5160,9 +5945,10 @@ gtk_window_get_gravity (GtkWindow *window) * * Starts resizing a window. This function is used if an application * has window resizing controls. When GDK can support it, the resize - * will be done using the standard mechanism for the window manager or - * windowing system. Otherwise, GDK will try to emulate window - * resizing, potentially not all that well, depending on the windowing system. + * will be done using the standard mechanism for the window manager or windowing + * system. Otherwise, GDK will try to emulate window resizing, + * potentially not all that well, depending on the windowing system. * **/ void @@ -5202,10 +5988,11 @@ gtk_window_begin_resize_drag (GtkWindow *window, * * (Note: this is a special-purpose function intended for the * framebuffer port; see gtk_window_set_has_frame(). It will not - * return the size of the window border drawn by the window manager, - * which is the normal case when using a windowing system. - * See gdk_window_get_frame_extents() to get the standard - * window border extents.) + * return the size of the window border drawn by the window manager, which is the normal + * case when using a windowing system. See + * gdk_window_get_frame_extents() to get the standard window border + * extents.) * * Retrieves the dimensions of the frame window for this toplevel. * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions(). @@ -5237,11 +6024,12 @@ gtk_window_get_frame_dimensions (GtkWindow *window, * @root_y: Y position where the user clicked to initiate the drag * @timestamp: timestamp from the click event that initiated the drag * - * Starts moving a window. This function is used if an application - * has window movement grips. When GDK can support it, the window movement - * will be done using the standard mechanism for the window manager or - * windowing system. Otherwise, GDK will try to emulate window - * movement, potentially not all that well, depending on the windowing system. + * Starts moving a window. This function is used if an application has + * window movement grips. When GDK can support it, the window movement + * will be done using the standard mechanism for the window manager or windowing + * system. Otherwise, GDK will try to emulate window movement, + * potentially not all that well, depending on the windowing system. * **/ void @@ -5270,16 +6058,93 @@ gtk_window_begin_move_drag (GtkWindow *window, timestamp); } +/** + * gtk_window_set_screen: + * @window: a #GtkWindow. + * @screen: a #GdkScreen. + * + * Sets the #GdkScreen where the @window is displayed; if + * the window is already mapped, it will be unmapped, and + * then remapped on the new screen. + * + * Since: 2.2 + */ +void +gtk_window_set_screen (GtkWindow *window, + GdkScreen *screen) +{ + GtkWidget *widget; + GdkScreen *previous_screen; + gboolean was_mapped; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_SCREEN (screen)); + + if (screen == window->screen) + return; + + widget = GTK_WIDGET (window); + + previous_screen = window->screen; + was_mapped = GTK_WIDGET_MAPPED (widget); + + if (was_mapped) + gtk_widget_unmap (widget); + if (GTK_WIDGET_REALIZED (widget)) + gtk_widget_unrealize (widget); + + gtk_window_free_key_hash (window); + window->screen = screen; + gtk_widget_reset_rc_styles (widget); + if (screen != previous_screen) + _gtk_widget_propagate_screen_changed (widget, previous_screen); + g_object_notify (G_OBJECT (window), "screen"); + + if (was_mapped) + gtk_widget_map (widget); +} + +static GdkScreen * +gtk_window_check_screen (GtkWindow *window) +{ + if (window->screen) + return window->screen; + else + { + g_warning ("Screen for GtkWindow not set; you must always set\n" + "a screen for a GtkWindow before using the window"); + return NULL; + } +} + +/** + * gtk_window_get_screen: + * @window: a #GtkWindow. + * + * Returns the #GdkScreen associated with @window. + * + * Return value: a #GdkScreen. + * + * Since: 2.2 + */ +GdkScreen* +gtk_window_get_screen (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + + return window->screen; +} + static void gtk_window_group_class_init (GtkWindowGroupClass *klass) { } -GtkType +GType gtk_window_group_get_type (void) { - static GtkType window_group_type = 0; + static GType window_group_type = 0; if (!window_group_type) { @@ -5389,7 +6254,7 @@ gtk_window_group_remove_window (GtkWindowGroup *window_group, window_group_cleanup_grabs (window_group, window); window->group = NULL; - g_object_unref (G_OBJECT (window_group)); + g_object_unref (window_group); g_object_unref (window); } @@ -5625,9 +6490,12 @@ gtk_window_parse_geometry (GtkWindow *window, guint w, h; GdkGravity grav; gboolean size_set, pos_set; + GdkScreen *screen; g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); g_return_val_if_fail (geometry != NULL, FALSE); + + screen = gtk_window_check_screen (window); result = gtk_XParseGeometry (geometry, &x, &y, &w, &h); @@ -5641,7 +6509,7 @@ gtk_window_parse_geometry (GtkWindow *window, size_set = FALSE; if ((result & WidthValue) || (result & HeightValue)) { - gtk_window_set_default_size (window, w, h); + gtk_window_set_default_size_internal (window, TRUE, w, TRUE, h, TRUE); size_set = TRUE; } @@ -5661,15 +6529,18 @@ gtk_window_parse_geometry (GtkWindow *window, if ((result & YValue) == 0) y = 0; - + if (grav == GDK_GRAVITY_SOUTH_WEST || grav == GDK_GRAVITY_SOUTH_EAST) - y = gdk_screen_height () - h; + y = gdk_screen_get_height (screen) - h + y; if (grav == GDK_GRAVITY_SOUTH_EAST || grav == GDK_GRAVITY_NORTH_EAST) - x = gdk_screen_width () - w; + x = gdk_screen_get_width (screen) - w + x; + /* we don't let you put a window offscreen; maybe some people would + * prefer to be able to, but it's kind of a bogus thing to do. + */ if (y < 0) y = 0; @@ -5699,3 +6570,290 @@ gtk_window_parse_geometry (GtkWindow *window, return result != 0; } + +static void +gtk_window_mnemonic_hash_foreach (gpointer key, + gpointer value, + gpointer data) +{ + struct { + GtkWindow *window; + GtkWindowKeysForeachFunc func; + gpointer func_data; + } *info = data; + + GtkWindowMnemonic *mnemonic = value; + + if (mnemonic->window == info->window) + (*info->func) (info->window, mnemonic->keyval, info->window->mnemonic_modifier, TRUE, info->func_data); +} + +void +_gtk_window_keys_foreach (GtkWindow *window, + GtkWindowKeysForeachFunc func, + gpointer func_data) +{ + GSList *groups; + + struct { + GtkWindow *window; + GtkWindowKeysForeachFunc func; + gpointer func_data; + } info; + + info.window = window; + info.func = func; + info.func_data = func_data; + + g_hash_table_foreach (mnemonic_hash_table, + gtk_window_mnemonic_hash_foreach, + &info); + + groups = gtk_accel_groups_from_object (G_OBJECT (window)); + while (groups) + { + GtkAccelGroup *group = groups->data; + gint i; + + for (i = 0; i < group->n_accels; i++) + { + GtkAccelKey *key = &group->priv_accels[i].key; + + if (key->accel_key) + (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data); + } + + groups = groups->next; + } +} + +static void +gtk_window_keys_changed (GtkWindow *window) +{ + gtk_window_free_key_hash (window); + gtk_window_get_key_hash (window); +} + +typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry; + +struct _GtkWindowKeyEntry +{ + guint keyval; + guint modifiers; + gboolean is_mnemonic; +}; + +static void +add_to_key_hash (GtkWindow *window, + guint keyval, + GdkModifierType modifiers, + gboolean is_mnemonic, + gpointer data) +{ + GtkKeyHash *key_hash = data; + + GtkWindowKeyEntry *entry = g_new (GtkWindowKeyEntry, 1); + + entry->keyval = keyval; + entry->modifiers = modifiers; + entry->is_mnemonic = is_mnemonic; + + /* GtkAccelGroup stores lowercased accelerators. To deal + * with this, if was specified, uppercase. + */ + if (modifiers & GDK_SHIFT_MASK) + { + if (keyval == GDK_Tab) + keyval = GDK_ISO_Left_Tab; + else + keyval = gdk_keyval_to_upper (keyval); + } + + _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry); +} + +static GtkKeyHash * +gtk_window_get_key_hash (GtkWindow *window) +{ + GdkScreen *screen = gtk_window_check_screen (window); + GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash"); + + if (key_hash) + return key_hash; + + key_hash = _gtk_key_hash_new (gdk_keymap_get_for_display (gdk_screen_get_display (screen)), + (GDestroyNotify)g_free); + _gtk_window_keys_foreach (window, add_to_key_hash, key_hash); + g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", key_hash); + + return key_hash; +} + +static void +gtk_window_free_key_hash (GtkWindow *window) +{ + GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash"); + if (key_hash) + { + _gtk_key_hash_free (key_hash); + g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", NULL); + } +} + +/** + * _gtk_window_activate_key: + * @window: a #GtkWindow + * @event: a #GdkEventKey + * + * Activates mnemonics and accelerators for this #GtKWindow + * + * Return value: %TRUE if a mnemonic or accelerator was found and activated. + **/ +gboolean +_gtk_window_activate_key (GtkWindow *window, + GdkEventKey *event) +{ + GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash"); + GtkWindowKeyEntry *found_entry = NULL; + + if (!key_hash) + { + gtk_window_keys_changed (window); + key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash"); + } + + if (key_hash) + { + GSList *entries = _gtk_key_hash_lookup (key_hash, + event->hardware_keycode, + event->state & gtk_accelerator_get_default_mod_mask (), + event->group); + GSList *tmp_list; + + for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next) + { + GtkWindowKeyEntry *entry = tmp_list->data; + if (entry->is_mnemonic) + { + found_entry = entry; + break; + } + } + + if (!found_entry && entries) + found_entry = entries->data; + + g_slist_free (entries); + } + + if (found_entry) + { + if (found_entry->is_mnemonic) + return gtk_window_mnemonic_activate (window, found_entry->keyval, found_entry->modifiers); + else + return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval, found_entry->modifiers); + } + else + return FALSE; +} + +static void +window_update_has_focus (GtkWindow *window) +{ + GtkWidget *widget = GTK_WIDGET (window); + gboolean has_focus = window->has_toplevel_focus && window->is_active; + + if (has_focus != window->has_focus) + { + window->has_focus = has_focus; + + if (has_focus) + { + if (window->focus_widget && + window->focus_widget != widget && + !GTK_WIDGET_HAS_FOCUS (window->focus_widget)) + do_focus_change (window->focus_widget, TRUE); + } + else + { + if (window->focus_widget && + window->focus_widget != widget && + GTK_WIDGET_HAS_FOCUS (window->focus_widget)) + do_focus_change (window->focus_widget, FALSE); + } + } +} + +/** + * _gtk_window_set_is_active: + * @window: a #GtkWindow + * @is_active: %TRUE if the window is in the currently active toplevel + * + * Internal function that sets whether the #GtkWindow is part + * of the currently active toplevel window (taking into account inter-process + * embedding.) + **/ +void +_gtk_window_set_is_active (GtkWindow *window, + gboolean is_active) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + + is_active = is_active != FALSE; + + if (is_active != window->is_active) + { + window->is_active = is_active; + window_update_has_focus (window); + + g_object_notify (G_OBJECT (window), "is_active"); + } +} + +/** + * _gtk_window_set_has_toplevel_focus: + * @window: a #GtkWindow + * @has_toplevel_focus: %TRUE if the in + * + * Internal function that sets whether the keyboard focus for the + * toplevel window (taking into account inter-process embedding.) + **/ +void +_gtk_window_set_has_toplevel_focus (GtkWindow *window, + gboolean has_toplevel_focus) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + + has_toplevel_focus = has_toplevel_focus != FALSE; + + if (has_toplevel_focus != window->has_toplevel_focus) + { + window->has_toplevel_focus = has_toplevel_focus; + window_update_has_focus (window); + + g_object_notify (G_OBJECT (window), "has_toplevel_focus"); + } +} + +/** + * gtk_window_set_auto_startup_notification: + * @setting: %TRUE to automatically do startup notification + * + * By default, after showing the first #GtkWindow for each #GdkScreen, + * GTK+ calls gdk_screen_notify_startup_complete(). Call this + * function to disable the automatic startup notification. You might + * do this if your first window is a splash screen, and you want to + * delay notification until after your real main window has been + * shown, for example. + * + * In that example, you would disable startup notification + * temporarily, show your splash screen, then re-enable it so that + * showing the main window would automatically result in notification. + * + * Since: 2.2 + **/ +void +gtk_window_set_auto_startup_notification (gboolean setting) +{ + disable_startup_notification = !setting; +}