X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkwindow.c;h=fe24363fd1e67ed58102b7530a2947ea08930346;hb=d434a9103c0fe2606b8aeeb1c629db9e9d1adbe6;hp=23a7de59903c361005fe1dff285851dde9e3843a;hpb=d4add8cefa6fa5c29bdb50f18e31cbfbfb38cc2b;p=~andy%2Fgtk diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 23a7de599..fe24363fd 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -34,7 +32,6 @@ #include #include "gtkprivate.h" -#include "gtkrc.h" #include "gtkwindowprivate.h" #include "gtkaccelgroupprivate.h" #include "gtkbindings.h" @@ -48,8 +45,13 @@ #include "gtkplug.h" #include "gtkbuildable.h" #include "gtkwidgetprivate.h" +#include "gtkcontainerprivate.h" #include "gtkintl.h" +#include "gtkstylecontextprivate.h" #include "gtktypebuiltins.h" +#include "a11y/gtkwindowaccessible.h" + +#include "deprecated/gtkstyle.h" #ifdef GDK_WINDOWING_X11 #include "x11/gdkx.h" @@ -96,25 +98,25 @@ * */ +#define AUTO_MNEMONICS_DELAY 300 /* ms */ + typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo; struct _GtkWindowPrivate { GtkMnemonicHash *mnemonic_hash; + GtkWidget *attach_widget; GtkWidget *default_widget; GtkWidget *focus_widget; GtkWindow *transient_parent; GtkWindowGeometryInfo *geometry_info; GtkWindowGroup *group; - - GdkModifierType mnemonic_modifier; GdkScreen *screen; - GdkWindowTypeHint gdk_type_hint; - GtkApplication *application; - gdouble opacity; + GdkModifierType mnemonic_modifier; + GdkWindowTypeHint gdk_type_hint; GdkWindow *grip_window; @@ -126,8 +128,12 @@ struct _GtkWindowPrivate guint keys_changed_handler; + guint32 initial_timestamp; + guint16 configure_request_count; + guint auto_mnemonics_timeout_id; + /* The following flags are initially TRUE (before a window is mapped). * They cause us to compute a configure request that involves * default-only parameters. Once mapped, we set them to FALSE. @@ -147,17 +153,17 @@ struct _GtkWindowPrivate guint destroy_with_parent : 1; guint focus_on_map : 1; guint fullscreen_initially : 1; - guint gravity : 5; /* GdkGravity */ guint has_focus : 1; guint has_user_ref_count : 1; guint has_toplevel_focus : 1; + guint hide_titlebar_when_maximized : 1; guint iconify_initially : 1; /* gtk_window_iconify() called before realization */ guint is_active : 1; guint maximize_initially : 1; guint mnemonics_visible : 1; guint mnemonics_visible_set : 1; + guint focus_visible : 1; guint modal : 1; - guint opacity_set : 1; guint position : 3; guint reset_type_hint : 1; guint resizable : 1; @@ -176,6 +182,7 @@ struct _GtkWindowPrivate guint resize_grip_visible : 1; /* don't use, just for "resize- * grip-visible" notification */ + guint gravity : 5; /* GdkGravity */ }; @@ -203,6 +210,7 @@ enum { PROP_DEFAULT_WIDTH, PROP_DEFAULT_HEIGHT, PROP_DESTROY_WITH_PARENT, + PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED, PROP_ICON, PROP_ICON_NAME, PROP_SCREEN, @@ -216,18 +224,19 @@ enum { PROP_DELETABLE, PROP_GRAVITY, PROP_TRANSIENT_FOR, - PROP_OPACITY, + PROP_ATTACHED_TO, PROP_HAS_RESIZE_GRIP, PROP_RESIZE_GRIP_VISIBLE, PROP_APPLICATION, /* Readonly properties */ PROP_IS_ACTIVE, PROP_HAS_TOPLEVEL_FOCUS, - + /* Writeonly properties */ PROP_STARTUP_ID, - + PROP_MNEMONICS_VISIBLE, + PROP_FOCUS_VISIBLE, LAST_ARG }; @@ -413,6 +422,12 @@ static GtkKeyHash *gtk_window_get_key_hash (GtkWindow *window); static void gtk_window_free_key_hash (GtkWindow *window); static void gtk_window_on_composited_changed (GdkScreen *screen, GtkWindow *window); +#ifdef GDK_WINDOWING_X11 +static void gtk_window_on_theme_variant_changed (GtkSettings *settings, + GParamSpec *pspec, + GtkWindow *window); +#endif +static void gtk_window_set_theme_variant (GtkWindow *window); static GSList *toplevel_list = NULL; static guint window_signals[LAST_SIGNAL] = { 0 }; @@ -458,13 +473,7 @@ static void gtk_window_buildable_custom_finished (GtkBuildable *buildable, const gchar *tagname, gpointer user_data); - -static void gtk_window_get_preferred_width (GtkWidget *widget, - gint *minimum_size, - gint *natural_size); -static void gtk_window_get_preferred_height (GtkWidget *widget, - gint *minimum_size, - gint *natural_size); +static void ensure_state_flag_backdrop (GtkWidget *widget); G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, @@ -576,8 +585,6 @@ gtk_window_class_init (GtkWindowClass *klass) widget_class->focus = gtk_window_focus; widget_class->move_focus = gtk_window_move_focus; widget_class->draw = gtk_window_draw; - widget_class->get_preferred_width = gtk_window_get_preferred_width; - widget_class->get_preferred_height = gtk_window_get_preferred_height; widget_class->window_state_event = gtk_window_state_event; widget_class->direction_changed = gtk_window_direction_changed; widget_class->state_changed = gtk_window_state_changed; @@ -689,6 +696,21 @@ gtk_window_class_init (GtkWindowClass *klass) FALSE, GTK_PARAM_READWRITE)); + /** + * GtkWindow:hide-titlebar-when-maximized: + * + * Whether the titlebar should be hidden during maximization. + * + * Since: 3.4 + */ + g_object_class_install_property (gobject_class, + PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED, + g_param_spec_boolean ("hide-titlebar-when-maximized", + P_("Hide the titlebar during maximization"), + P_("If this window's titlebar should be hidden when the window is maximized"), + FALSE, + GTK_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_ICON, g_param_spec_object ("icon", @@ -696,6 +718,18 @@ gtk_window_class_init (GtkWindowClass *klass) P_("Icon for this window"), GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); + + /** + * GtkWindow:mnemonics-visible: + * + * Whether mnemonics are currently visible in this window. + * + * This property is maintained by GTK+ based on the + * #GtkSettings:gtk-auto-mnemonics setting and user input, + * and should not be set by applications. + * + * Since: 2.20 + */ g_object_class_install_property (gobject_class, PROP_MNEMONICS_VISIBLE, g_param_spec_boolean ("mnemonics-visible", @@ -703,6 +737,25 @@ gtk_window_class_init (GtkWindowClass *klass) P_("Whether mnemonics are currently visible in this window"), TRUE, GTK_PARAM_READWRITE)); + + /** + * GtkWindow:focus-visible: + * + * Whether 'focus rectangles' are currently visible in this window. + * + * This property is maintained by GTK+ based on the + * #GtkSettings:gtk-visible-focus setting and user input + * and should not be set by applications. + * + * Since: 2.20 + */ + g_object_class_install_property (gobject_class, + PROP_FOCUS_VISIBLE, + g_param_spec_boolean ("focus-visible", + P_("Focus Visible"), + P_("Whether focus rectangles are currently visible in this window"), + TRUE, + GTK_PARAM_READWRITE)); /** * GtkWindow:icon-name: @@ -838,7 +891,7 @@ gtk_window_class_init (GtkWindowClass *klass) GTK_PARAM_READWRITE)); /** - * GtkWindow:has-resize-grip + * GtkWindow:has-resize-grip: * * Whether the window has a corner resize grip. * @@ -908,22 +961,25 @@ gtk_window_class_init (GtkWindowClass *klass) GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT)); /** - * GtkWindow:opacity: + * GtkWindow:attached-to: * - * The requested opacity of the window. See gtk_window_set_opacity() for - * more details about window opacity. + * The widget to which this window is attached. + * See gtk_window_set_attached_to(). * - * Since: 2.12 + * Examples of places where specifying this relation is useful are + * for instance a #GtkMenu created by a #GtkComboBox, a completion + * popup window created by #GtkEntry or a typeahead search entry + * created by #GtkTreeView. + * + * Since: 3.4 */ g_object_class_install_property (gobject_class, - PROP_OPACITY, - g_param_spec_double ("opacity", - P_("Opacity for Window"), - P_("The opacity of the window, from 0 to 1"), - 0.0, - 1.0, - 1.0, - GTK_PARAM_READWRITE)); + PROP_ATTACHED_TO, + g_param_spec_object ("attached-to", + P_("Attached to Widget"), + P_("The widget where the window is attached"), + GTK_TYPE_WIDGET, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT)); /* Style properties. */ @@ -1055,11 +1111,14 @@ gtk_window_class_init (GtkWindowClass *klass) 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); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_WINDOW_ACCESSIBLE); } static void gtk_window_init (GtkWindow *window) { + GtkStyleContext *context; GtkWindowPrivate *priv; window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window, @@ -1099,10 +1158,11 @@ gtk_window_init (GtkWindow *window) priv->focus_on_map = TRUE; priv->deletable = TRUE; priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; - priv->opacity = 1.0; priv->startup_id = NULL; + priv->initial_timestamp = GDK_CURRENT_TIME; priv->has_resize_grip = TRUE; priv->mnemonics_visible = TRUE; + priv->focus_visible = TRUE; g_object_ref_sink (window); priv->has_user_ref_count = TRUE; @@ -1111,6 +1171,15 @@ gtk_window_init (GtkWindow *window) if (priv->screen) g_signal_connect (priv->screen, "composited-changed", G_CALLBACK (gtk_window_on_composited_changed), window); + +#ifdef GDK_WINDOWING_X11 + g_signal_connect (gtk_settings_get_for_screen (priv->screen), + "notify::gtk-application-prefer-dark-theme", + G_CALLBACK (gtk_window_on_theme_variant_changed), window); +#endif + + context = gtk_widget_get_style_context (GTK_WIDGET (window)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND); } static void @@ -1158,6 +1227,9 @@ gtk_window_set_property (GObject *object, case PROP_DESTROY_WITH_PARENT: gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value)); break; + case PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED: + gtk_window_set_hide_titlebar_when_maximized (window, g_value_get_boolean (value)); + break; case PROP_ICON: gtk_window_set_icon (window, g_value_get_object (value)); @@ -1204,8 +1276,8 @@ gtk_window_set_property (GObject *object, case PROP_TRANSIENT_FOR: gtk_window_set_transient_for (window, g_value_get_object (value)); break; - case PROP_OPACITY: - gtk_window_set_opacity (window, g_value_get_double (value)); + case PROP_ATTACHED_TO: + gtk_window_set_attached_to (window, g_value_get_object (value)); break; case PROP_HAS_RESIZE_GRIP: gtk_window_set_has_resize_grip (window, g_value_get_boolean (value)); @@ -1216,6 +1288,9 @@ gtk_window_set_property (GObject *object, case PROP_MNEMONICS_VISIBLE: gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value)); break; + case PROP_FOCUS_VISIBLE: + gtk_window_set_focus_visible (window, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1269,6 +1344,9 @@ gtk_window_get_property (GObject *object, case PROP_DESTROY_WITH_PARENT: g_value_set_boolean (value, priv->destroy_with_parent); break; + case PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED: + g_value_set_boolean (value, priv->hide_titlebar_when_maximized); + break; case PROP_ICON: g_value_set_object (value, gtk_window_get_icon (window)); break; @@ -1319,8 +1397,8 @@ gtk_window_get_property (GObject *object, case PROP_TRANSIENT_FOR: g_value_set_object (value, gtk_window_get_transient_for (window)); break; - case PROP_OPACITY: - g_value_set_double (value, gtk_window_get_opacity (window)); + case PROP_ATTACHED_TO: + g_value_set_object (value, gtk_window_get_attached_to (window)); break; case PROP_HAS_RESIZE_GRIP: g_value_set_boolean (value, priv->has_resize_grip); @@ -1334,6 +1412,9 @@ gtk_window_get_property (GObject *object, case PROP_MNEMONICS_VISIBLE: g_value_set_boolean (value, priv->mnemonics_visible); break; + case PROP_FOCUS_VISIBLE: + g_value_set_boolean (value, priv->focus_visible); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1571,7 +1652,7 @@ gtk_window_set_title (GtkWindow *window, * been set explicitely. The returned string is owned by the widget * and must not be modified or freed. **/ -G_CONST_RETURN gchar * +const gchar * gtk_window_get_title (GtkWindow *window) { g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); @@ -1698,7 +1779,7 @@ gtk_window_set_startup_id (GtkWindow *window, gdk_window = gtk_widget_get_window (widget); #ifdef GDK_WINDOWING_X11 - if (timestamp != GDK_CURRENT_TIME) + if (timestamp != GDK_CURRENT_TIME && GDK_IS_X11_WINDOW(gdk_window)) gdk_x11_window_set_user_time (gdk_window, timestamp); #endif @@ -1733,7 +1814,7 @@ gtk_window_set_startup_id (GtkWindow *window, * returned is owned by the widget and must not be modified * or freed. **/ -G_CONST_RETURN gchar * +const gchar * gtk_window_get_role (GtkWindow *window) { g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); @@ -1817,8 +1898,8 @@ _gtk_window_internal_set_focus (GtkWindow *window, * unsets the default widget for a #GtkWindow about. When setting * (rather than unsetting) the default widget it's generally easier to * call gtk_widget_grab_focus() on the widget. Before making a widget - * the default widget, you must set the #GTK_CAN_DEFAULT flag on the - * widget you'd like to make the default using GTK_WIDGET_SET_FLAGS(). + * the default widget, you must call gtk_widget_set_can_default() on the + * widget you'd like to make the default. **/ void gtk_window_set_default (GtkWindow *window, @@ -2020,10 +2101,11 @@ gtk_window_remove_mnemonic (GtkWindow *window, * gtk_window_mnemonic_activate: * @window: a #GtkWindow * @keyval: the mnemonic - * @modifier: the modifiers - * @returns: %TRUE if the activation is done. - * + * @modifier: the modifiers + * * Activates the targets associated with the mnemonic. + * + * Returns: %TRUE if the activation is done. */ gboolean gtk_window_mnemonic_activate (GtkWindow *window, @@ -2292,6 +2374,20 @@ gtk_window_list_toplevels (void) return list; } +static void +remove_attach_widget (GtkWindow *window) +{ + GtkWindowPrivate *priv = window->priv; + + if (priv->attach_widget) + { + _gtk_widget_remove_attached_window (priv->attach_widget, window); + + g_object_unref (priv->attach_widget); + priv->attach_widget = NULL; + } +} + static void gtk_window_dispose (GObject *object) { @@ -2300,6 +2396,8 @@ gtk_window_dispose (GObject *object) gtk_window_set_focus (window, NULL); gtk_window_set_default (window, NULL); + remove_attach_widget (GTK_WINDOW (object)); + G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object); } @@ -2490,6 +2588,82 @@ gtk_window_get_transient_for (GtkWindow *window) return window->priv->transient_parent; } +/** + * gtk_window_set_attached_to: + * @window: a #GtkWindow + * @attach_widget: (allow-none): a #GtkWidget, or %NULL + * + * Marks @window as attached to @attach_widget. This creates a logical binding + * between the window and the widget it belongs to, which is used by GTK+ to + * propagate information such as styling or accessibility to @window as if it + * was a children of @attach_widget. + * + * Examples of places where specifying this relation is useful are for instance + * a #GtkMenu created by a #GtkComboBox, a completion popup window + * created by #GtkEntry or a typeahead search entry created by #GtkTreeView. + * + * Note that this function should not be confused with + * gtk_window_set_transient_for(), which specifies a window manager relation + * between two toplevels instead. + * + * Passing %NULL for @attach_widget detaches the window. + * + * Since: 3.4 + **/ +void +gtk_window_set_attached_to (GtkWindow *window, + GtkWidget *attach_widget) +{ + GtkStyleContext *context; + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (GTK_WIDGET (window) != attach_widget); + + priv = window->priv; + + if (priv->attach_widget == attach_widget) + return; + + remove_attach_widget (window); + + priv->attach_widget = attach_widget; + + if (priv->attach_widget) + { + _gtk_widget_add_attached_window (priv->attach_widget, window); + + g_object_ref (priv->attach_widget); + } + + /* Update the style, as the widget path might change. */ + context = gtk_widget_get_style_context (GTK_WIDGET (window)); + if (priv->attach_widget) + gtk_style_context_set_parent (context, gtk_widget_get_style_context (priv->attach_widget)); + else + gtk_style_context_set_parent (context, NULL); +} + +/** + * gtk_window_get_attached_to: + * @window: a #GtkWindow + * + * Fetches the attach widget for this window. See + * gtk_window_set_attached_to(). + * + * Return value: (transfer none): the widget where the window is attached, + * or %NULL if the window is not attached to any widget. + * + * Since: 3.4 + **/ +GtkWidget * +gtk_window_get_attached_to (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + + return window->priv->attach_widget; +} + /** * gtk_window_set_opacity: * @window: a #GtkWindow @@ -2506,28 +2680,13 @@ gtk_window_get_transient_for (GtkWindow *window) * shown causes it to flicker once on Windows. * * Since: 2.12 + * Deprecated: 3.8: Use gtk_widget_set_opacity instead. **/ void gtk_window_set_opacity (GtkWindow *window, gdouble opacity) { - GtkWindowPrivate *priv; - - g_return_if_fail (GTK_IS_WINDOW (window)); - - priv = window->priv; - - if (opacity < 0.0) - opacity = 0.0; - else if (opacity > 1.0) - opacity = 1.0; - - priv->opacity_set = TRUE; - priv->opacity = opacity; - - if (gtk_widget_get_realized (GTK_WIDGET (window))) - gdk_window_set_opacity (gtk_widget_get_window (GTK_WIDGET (window)), - priv->opacity); + gtk_widget_set_opacity (GTK_WIDGET (window), opacity); } /** @@ -2540,13 +2699,14 @@ gtk_window_set_opacity (GtkWindow *window, * Return value: the requested opacity for this window. * * Since: 2.12 + * Deprecated: 3.8: Use gtk_widget_get_opacity instead. **/ gdouble gtk_window_get_opacity (GtkWindow *window) { g_return_val_if_fail (GTK_IS_WINDOW (window), 0.0); - return window->priv->opacity; + return gtk_widget_get_opacity (GTK_WIDGET (window)); } /** @@ -2617,6 +2777,9 @@ gtk_window_set_application (GtkWindow *window, gtk_application_add_window (priv->application, window); } + /* don't use a normal cast: application may be NULL */ + gtk_widget_insert_action_group (GTK_WIDGET (window), "app", (GActionGroup *) application); + g_object_notify (G_OBJECT (window), "application"); } } @@ -2648,12 +2811,12 @@ gtk_window_set_type_hint (GtkWindow *window, priv = window->priv; if (hint < GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU) - priv->gdk_type_hint = hint; + priv->type_hint = hint; else - priv->gdk_type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; + priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; priv->reset_type_hint = TRUE; - priv->type_hint = hint; + priv->gdk_type_hint = hint; } /** @@ -2669,7 +2832,7 @@ gtk_window_get_type_hint (GtkWindow *window) { g_return_val_if_fail (GTK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL); - return window->priv->type_hint; + return window->priv->gdk_type_hint; } /** @@ -2981,6 +3144,61 @@ gtk_window_get_destroy_with_parent (GtkWindow *window) return window->priv->destroy_with_parent; } +/** + * gtk_window_set_hide_titlebar_when_maximized: + * @window: a #GtkWindow + * @setting: whether to hide the titlebar when @window is maximized + * + * If @setting is %TRUE, then @window will request that it's titlebar + * should be hidden when maximized. + * This is useful for windows that don't convey any information other + * than the application name in the titlebar, to put the available + * screen space to better use. If the underlying window system does not + * support the request, the setting will not have any effect. + * + * Since: 3.4 + **/ +void +gtk_window_set_hide_titlebar_when_maximized (GtkWindow *window, + gboolean setting) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + +#ifdef GDK_WINDOWING_X11 + { + GdkWindow *gdk_window; + + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + + if (GDK_IS_X11_WINDOW (gdk_window)) + gdk_x11_window_set_hide_titlebar_when_maximized (gdk_window, setting); + } +#endif + + window->priv->hide_titlebar_when_maximized = setting; + g_object_notify (G_OBJECT (window), "hide-titlebar-when-maximized"); +} + +/** + * gtk_window_get_hide_titlebar_when_maximized: + * @window: a #GtkWindow + * + * Returns whether the window has requested to have its titlebar hidden + * when maximized. See gtk_window_set_hide_titlebar_when_maximized (). + * + * Return value: %TRUE if the window has requested to have its titlebar + * hidden when maximized + * + * Since: 3.4 + **/ +gboolean +gtk_window_get_hide_titlebar_when_maximized (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + return window->priv->hide_titlebar_when_maximized; +} + static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window, gboolean create) @@ -3143,7 +3361,7 @@ gtk_window_get_decorated (GtkWindow *window) * using this function, GTK+ will do its best to convince the window * manager not to show a close button. 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(). + * already visible, so you should call it before calling gtk_widget_show(). * * On Windows, this function always works, since there's no window manager * policy involved. @@ -3344,8 +3562,7 @@ gtk_window_realize_icon (GtkWindow *window) { GtkIconTheme *icon_theme; - g_list_foreach (icon_list, (GFunc) g_object_unref, NULL); - g_list_free (icon_list); + g_list_free_full (icon_list, g_object_unref); icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window))); g_signal_connect (icon_theme, "changed", @@ -3426,10 +3643,7 @@ gtk_window_set_icon_list (GtkWindow *window, g_list_foreach (list, (GFunc) g_object_ref, NULL); - g_list_foreach (info->icon_list, - (GFunc) g_object_unref, NULL); - - g_list_free (info->icon_list); + g_list_free_full (info->icon_list, g_object_unref); info->icon_list = g_list_copy (list); @@ -3557,8 +3771,7 @@ gtk_window_set_icon_name (GtkWindow *window, info->icon_name = g_strdup (name); g_free (tmp); - g_list_foreach (info->icon_list, (GFunc) g_object_unref, NULL); - g_list_free (info->icon_list); + g_list_free_full (info->icon_list, g_object_unref); info->icon_list = NULL; update_themed_icon (NULL, window); @@ -3701,10 +3914,7 @@ gtk_window_set_default_icon_list (GList *list) g_list_foreach (list, (GFunc) g_object_ref, NULL); - g_list_foreach (default_icon_list, - (GFunc) g_object_unref, NULL); - - g_list_free (default_icon_list); + g_list_free_full (default_icon_list, g_object_unref); default_icon_list = g_list_copy (list); @@ -3773,10 +3983,7 @@ gtk_window_set_default_icon_name (const gchar *name) g_free (default_icon_name); default_icon_name = g_strdup (name); - g_list_foreach (default_icon_list, - (GFunc) g_object_unref, NULL); - - g_list_free (default_icon_list); + g_list_free_full (default_icon_list, g_object_unref); default_icon_list = NULL; /* Update all toplevels */ @@ -4277,14 +4484,16 @@ gtk_window_move (GtkWindow *window, /** * gtk_window_get_position: * @window: a #GtkWindow - * @root_x: (out): return location for X coordinate of gravity-determined reference point - * @root_y: (out): return location for Y coordinate of gravity-determined reference point + * @root_x: (out) (allow-none): return location for X coordinate of + * gravity-determined reference point, or %NULL + * @root_y: (out) (allow-none): return location for Y coordinate of + * gravity-determined reference point, or %NULL * * This function returns the position you need to pass to - * gtk_window_move() to keep @window in its current position. This - * means that the meaning of the returned value varies with window - * gravity. See gtk_window_move() for more details. - * + * gtk_window_move() to keep @window in its current position. + * This means that the meaning of the returned value varies with + * window gravity. See gtk_window_move() for more details. + * * If you haven't changed the window gravity, its gravity will be * #GDK_GRAVITY_NORTH_WEST. This means that gtk_window_get_position() * gets the position of the top-left corner of the window manager @@ -4474,6 +4683,8 @@ gtk_window_destroy (GtkWidget *widget) if (priv->transient_parent) gtk_window_set_transient_for (window, NULL); + remove_attach_widget (GTK_WINDOW (widget)); + /* frees the icons */ gtk_window_set_icon_list (window, NULL); @@ -4529,6 +4740,18 @@ gtk_window_finalize (GObject *object) g_free (priv->startup_id); + if (priv->auto_mnemonics_timeout_id) + { + g_source_remove (priv->auto_mnemonics_timeout_id); + priv->auto_mnemonics_timeout_id = 0; + } + +#ifdef GDK_WINDOWING_X11 + g_signal_handlers_disconnect_by_func (gtk_settings_get_default (), + gtk_window_on_theme_variant_changed, + window); +#endif + G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object); } @@ -4538,6 +4761,7 @@ gtk_window_show (GtkWidget *widget) GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = window->priv; GtkContainer *container = GTK_CONTAINER (window); + GtkBitmask *empty; gboolean need_resize; gboolean is_plug; @@ -4549,8 +4773,14 @@ gtk_window_show (GtkWidget *widget) _gtk_widget_set_visible_flag (widget, TRUE); - need_resize = _gtk_container_get_need_resize (container) || !gtk_widget_get_realized (widget); - _gtk_container_set_need_resize (container, FALSE); + need_resize = _gtk_widget_get_alloc_needed (widget) || !gtk_widget_get_realized (widget); + + empty = _gtk_bitmask_new (); + _gtk_style_context_validate (gtk_widget_get_style_context (widget), + g_get_monotonic_time (), + 0, + empty); + _gtk_bitmask_free (empty); if (need_resize) { @@ -4612,7 +4842,8 @@ gtk_window_show (GtkWidget *widget) /* Try to make sure that we have some focused widget */ #ifdef GDK_WINDOWING_X11 - is_plug = GTK_IS_PLUG (window); + is_plug = GDK_IS_X11_WINDOW (gtk_widget_get_window (widget)) && + GTK_IS_PLUG (window); #else is_plug = FALSE; #endif @@ -4648,13 +4879,11 @@ gtk_window_map (GtkWidget *widget) GtkWidget *child; GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = window->priv; - GdkWindow *toplevel; GdkWindow *gdk_window; gboolean auto_mnemonics; + GtkPolicyType visible_focus; - gdk_window = gtk_widget_get_window (widget); - - if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + if (!gtk_widget_is_toplevel (widget)) { GTK_WIDGET_CLASS (gtk_window_parent_class)->map (widget); return; @@ -4668,36 +4897,43 @@ gtk_window_map (GtkWidget *widget) !gtk_widget_get_mapped (child)) gtk_widget_map (child); - toplevel = gdk_window; + gdk_window = gtk_widget_get_window (widget); if (priv->maximize_initially) - gdk_window_maximize (toplevel); + gdk_window_maximize (gdk_window); else - gdk_window_unmaximize (toplevel); - + gdk_window_unmaximize (gdk_window); + if (priv->stick_initially) - gdk_window_stick (toplevel); + gdk_window_stick (gdk_window); else - gdk_window_unstick (toplevel); - + gdk_window_unstick (gdk_window); + if (priv->iconify_initially) - gdk_window_iconify (toplevel); + gdk_window_iconify (gdk_window); else - gdk_window_deiconify (toplevel); + gdk_window_deiconify (gdk_window); if (priv->fullscreen_initially) - gdk_window_fullscreen (toplevel); + gdk_window_fullscreen (gdk_window); else - gdk_window_unfullscreen (toplevel); - - gdk_window_set_keep_above (toplevel, priv->above_initially); + gdk_window_unfullscreen (gdk_window); + + gdk_window_set_keep_above (gdk_window, priv->above_initially); - gdk_window_set_keep_below (toplevel, priv->below_initially); + gdk_window_set_keep_below (gdk_window, priv->below_initially); + + if (priv->type == GTK_WINDOW_TOPLEVEL) + { + gtk_window_set_theme_variant (window); + gtk_window_set_hide_titlebar_when_maximized (window, + priv->hide_titlebar_when_maximized); + } /* No longer use the default settings */ priv->need_default_size = FALSE; priv->need_default_position = FALSE; - + if (priv->reset_type_hint) { /* We should only reset the type hint when the application @@ -4705,7 +4941,7 @@ gtk_window_map (GtkWidget *widget) * Some applications use X directly to change the properties; * in that case, we shouldn't overwrite what they did. */ - gdk_window_set_type_hint (gdk_window, priv->type_hint); + gdk_window_set_type_hint (gdk_window, priv->gdk_type_hint); priv->reset_type_hint = FALSE; } @@ -4720,7 +4956,7 @@ gtk_window_map (GtkWidget *widget) if (priv->startup_id != NULL) { /* Make sure we have a "real" id */ - if (!startup_id_is_fake (priv->startup_id)) + if (!startup_id_is_fake (priv->startup_id)) gdk_notify_startup_complete_with_id (priv->startup_id); g_free (priv->startup_id); @@ -4736,10 +4972,21 @@ gtk_window_map (GtkWidget *widget) /* if auto-mnemonics is enabled and mnemonics visible is not already set * (as in the case of popup menus), then hide mnemonics initially */ - g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics", - &auto_mnemonics, NULL); + g_object_get (gtk_widget_get_settings (widget), + "gtk-auto-mnemonics", &auto_mnemonics, + "gtk-visible-focus", &visible_focus, + NULL); + if (auto_mnemonics && !priv->mnemonics_visible_set) gtk_window_set_mnemonics_visible (window, FALSE); + + /* inherit from transient parent, so that a dialog that is + * opened via keynav shows focus initially + */ + if (priv->transient_parent) + gtk_window_set_focus_visible (window, gtk_window_get_focus_visible (priv->transient_parent)); + else + gtk_window_set_focus_visible (window, visible_focus == GTK_POLICY_ALWAYS); } static gboolean @@ -4809,6 +5056,73 @@ gtk_window_unmap (GtkWidget *widget) gtk_widget_unmap (child); } +/* (Note: Replace "size" with "width" or "height". Also, the request + * mode is honoured.) + * For selecting the default window size, the following conditions + * should hold (in order of importance): + * - the size is not below the minimum size + * Windows cannot be resized below their minimum size, so we must + * ensure we don't do that either. + * - the size is not above the natural size + * It seems weird to allocate more than this in an initial guess. + * - the size does not exceed that of a maximized window + * We want to see the whole window after all. + * (Note that this may not be possible to achieve due to imperfect + * information from the windowing system.) + */ + +/* We use these for now to not make windows too big by accident. Note + * that we still clamp these numbers by screen size. Also note that + * minimum size still overrides this. So keep your windows small! :) + */ +#define MAX_DEFAULT_WINDOW_WIDTH 640 +#define MAX_DEFAULT_WINDOW_HEIGHT 480 + +static void +gtk_window_guess_default_size (GtkWindow *window, + gint *width, + gint *height) +{ + GtkWidget *widget = GTK_WIDGET (window); + GdkScreen *screen; + int minimum, natural; + + screen = gtk_widget_get_screen (widget); + + *width = gdk_screen_get_width (screen); + *height = gdk_screen_get_height (screen); + + if (*width >= *height) + { + /* landscape */ + *width = MIN (*width, MAX_DEFAULT_WINDOW_WIDTH); + *height = MIN (*height, MAX_DEFAULT_WINDOW_HEIGHT); + } + else + { + /* portrait */ + *width = MIN (*width, MAX_DEFAULT_WINDOW_HEIGHT); + *height = MIN (*height, MAX_DEFAULT_WINDOW_WIDTH); + } + + if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT) + { + gtk_widget_get_preferred_height (widget, &minimum, &natural); + *height = MAX (minimum, MIN (*height, natural)); + + gtk_widget_get_preferred_width_for_height (widget, *height, &minimum, &natural); + *width = MAX (minimum, MIN (*width, natural)); + } + else /* GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH or CONSTANT_SIZE */ + { + gtk_widget_get_preferred_width (widget, &minimum, &natural); + *width = MAX (minimum, MIN (*width, natural)); + + gtk_widget_get_preferred_height_for_width (widget, *width, &minimum, &natural); + *height = MAX (minimum, MIN (*height, natural)); + } +} + static void gtk_window_realize (GtkWidget *widget) { @@ -4848,11 +5162,10 @@ gtk_window_realize (GtkWidget *widget) gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gtk_widget_set_window (widget, gdk_window); - gdk_window_set_user_data (gdk_window, widget); + gtk_widget_register_window (widget, gdk_window); gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window); - gdk_window_enable_synchronized_configure (gdk_window); return; } @@ -4864,19 +5177,16 @@ gtk_window_realize (GtkWidget *widget) allocation.width == 1 && allocation.height == 1) { - GtkRequisition requisition; allocation.x = 0; allocation.y = 0; - allocation.width = 200; - allocation.height = 200; - gtk_widget_get_preferred_size (widget, &requisition, NULL); - if (requisition.width || requisition.height) + gtk_window_guess_default_size (window, &allocation.width, &allocation.height); + if (allocation.width == 0 || allocation.height == 0) { /* non-empty window */ - allocation.width = requisition.width; - allocation.height = requisition.height; + allocation.width = 200; + allocation.height = 200; } gtk_widget_size_allocate (widget, &allocation); @@ -4929,12 +5239,7 @@ gtk_window_realize (GtkWidget *widget) gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask); gtk_widget_set_window (widget, gdk_window); - if (priv->opacity_set) - gdk_window_set_opacity (gdk_window, priv->opacity); - - gdk_window_enable_synchronized_configure (gdk_window); - - gdk_window_set_user_data (gdk_window, window); + gtk_widget_register_window (widget, gdk_window); context = gtk_widget_get_style_context (widget); gtk_style_context_set_background (context, gdk_window); @@ -4974,18 +5279,29 @@ gtk_window_realize (GtkWidget *widget) gdk_window_set_modal_hint (gdk_window, TRUE); else gdk_window_set_modal_hint (gdk_window, FALSE); - + if (priv->startup_id) { #ifdef GDK_WINDOWING_X11 - guint32 timestamp = extract_time_from_startup_id (priv->startup_id); - if (timestamp != GDK_CURRENT_TIME) - gdk_x11_window_set_user_time (gdk_window, timestamp); + if (GDK_IS_X11_WINDOW (gdk_window)) + { + guint32 timestamp = extract_time_from_startup_id (priv->startup_id); + if (timestamp != GDK_CURRENT_TIME) + gdk_x11_window_set_user_time (gdk_window, timestamp); + } #endif - if (!startup_id_is_fake (priv->startup_id)) - gdk_window_set_startup_id (gdk_window, priv->startup_id); + if (!startup_id_is_fake (priv->startup_id)) + gdk_window_set_startup_id (gdk_window, priv->startup_id); } - + +#ifdef GDK_WINDOWING_X11 + if (priv->initial_timestamp != GDK_CURRENT_TIME) + { + if (GDK_IS_X11_WINDOW (gdk_window)) + gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp); + } +#endif + /* Icons */ gtk_window_realize_icon (window); @@ -5142,7 +5458,7 @@ set_grip_shape (GtkWindow *window) width = gdk_window_get_width (priv->grip_window); height = gdk_window_get_height (priv->grip_window); - surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + surface = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height); cr = cairo_create (surface); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); @@ -5186,34 +5502,55 @@ set_grip_position (GtkWindow *window) rect.width, rect.height); } -static void -gtk_window_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +/* _gtk_window_set_allocation: + * @window: a #GtkWindow + * @allocation: the new allocation + * + * This function is like gtk_widget_set_allocation() + * but does the necessary extra work to update + * the resize grip positioning, etc. + * + * Call this instead of gtk_widget_set_allocation() + * when overriding ::size_allocate in a GtkWindow + * subclass without chaining up. + */ +void +_gtk_window_set_allocation (GtkWindow *window, + GtkAllocation *allocation) { - GtkWindow *window = GTK_WINDOW (widget); - GtkAllocation child_allocation; - GtkWidget *child; - guint border_width; + GtkWidget *widget = (GtkWidget *)window; gtk_widget_set_allocation (widget, allocation); if (gtk_widget_get_realized (widget)) { - /* If it's not a toplevel we're embedded, we need to resize the window's - * window and skip the grip. + /* If it's not a toplevel we're embedded, we need to resize + * the window's window and skip the grip. */ if (!gtk_widget_is_toplevel (widget)) - { - gdk_window_move_resize (gtk_widget_get_window (widget), - allocation->x, allocation->y, - allocation->width, allocation->height); - } + { + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, allocation->y, + allocation->width, allocation->height); + } else - { - update_grip_visibility (window); - set_grip_position (window); - } + { + update_grip_visibility (window); + set_grip_position (window); + } } +} + +static void +gtk_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWindow *window = GTK_WINDOW (widget); + GtkAllocation child_allocation; + GtkWidget *child; + guint border_width; + + _gtk_window_set_allocation (window, allocation); child = gtk_bin_get_child (&(window->bin)); if (child && gtk_widget_get_visible (child)) @@ -5221,10 +5558,8 @@ gtk_window_size_allocate (GtkWidget *widget, border_width = gtk_container_get_border_width (GTK_CONTAINER (window)); child_allocation.x = border_width; child_allocation.y = border_width; - child_allocation.width = - MAX (1, (gint)allocation->width - child_allocation.x * 2); - child_allocation.height = - MAX (1, (gint)allocation->height - child_allocation.y * 2); + child_allocation.width = MAX (1, allocation->width - border_width * 2); + child_allocation.height = MAX (1, allocation->height - border_width * 2); gtk_widget_size_allocate (child, &child_allocation); } @@ -5244,7 +5579,6 @@ gtk_window_configure_event (GtkWidget *widget, if (GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event) return GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event (widget, event); - gdk_window_configure_finished (gtk_widget_get_window (widget)); return FALSE; } @@ -5278,13 +5612,11 @@ gtk_window_configure_event (GtkWidget *widget, (allocation.width == event->width && allocation.height == event->height)) { - gdk_window_configure_finished (gtk_widget_get_window (widget)); return TRUE; } /* * If we do need to resize, we do that by: - * - filling in widget->allocation with the new size * - setting configure_notify_received to TRUE * for use in gtk_window_move_resize() * - queueing a resize, leading to invocation of @@ -5294,10 +5626,6 @@ gtk_window_configure_event (GtkWidget *widget, priv->configure_notify_received = TRUE; - allocation.width = event->width; - allocation.height = event->height; - gtk_widget_set_allocation (widget, &allocation); - gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); // XXX - What was this for again? _gtk_container_queue_resize (GTK_CONTAINER (widget)); @@ -5311,6 +5639,9 @@ gtk_window_state_event (GtkWidget *widget, { update_grip_visibility (GTK_WINDOW (widget)); + if (event->changed_mask & GDK_WINDOW_STATE_FOCUSED) + ensure_state_flag_backdrop (widget); + return FALSE; } @@ -5350,7 +5681,6 @@ gtk_window_style_updated (GtkWidget *widget) rect.width, rect.height); set_grip_shape (window); - gtk_widget_queue_resize (widget); } } @@ -5362,6 +5692,7 @@ resize_grip_create_window (GtkWindow *window) GdkWindowAttr attributes; gint attributes_mask; GdkRectangle rect; + GdkRGBA transparent = {0, 0, 0, 0}; priv = window->priv; widget = GTK_WIDGET (window); @@ -5386,8 +5717,9 @@ resize_grip_create_window (GtkWindow *window) priv->grip_window = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); + gdk_window_set_background_rgba (priv->grip_window, &transparent); - gdk_window_set_user_data (priv->grip_window, widget); + gtk_widget_register_window (widget, priv->grip_window); gdk_window_raise (priv->grip_window); @@ -5400,7 +5732,7 @@ resize_grip_destroy_window (GtkWindow *window) { GtkWindowPrivate *priv = window->priv; - gdk_window_set_user_data (priv->grip_window, NULL); + gtk_widget_unregister_window (GTK_WIDGET (window), priv->grip_window); gdk_window_destroy (priv->grip_window); priv->grip_window = NULL; update_grip_visibility (window); @@ -5555,7 +5887,7 @@ gtk_window_get_has_resize_grip (GtkWindow *window) * Since: 3.0 */ gboolean -gtk_window_get_resize_grip_area (GtkWindow *window, +gtk_window_get_resize_grip_area (GtkWindow *window, GdkRectangle *rect) { GtkWidget *widget = GTK_WIDGET (window); @@ -5741,12 +6073,13 @@ gtk_window_button_press_event (GtkWidget *widget, if (event->window == priv->grip_window) { if (get_drag_edge (widget, &edge)) - gtk_window_begin_resize_drag (GTK_WINDOW (widget), - edge, - event->button, - event->x_root, - event->y_root, - event->time); + gdk_window_begin_resize_drag_for_device (gtk_widget_get_window (widget), + edge, + gdk_event_get_device ((GdkEvent *) event), + event->button, + event->x_root, + event->y_root, + event->time); return TRUE; } @@ -5829,11 +6162,42 @@ do_focus_change (GtkWidget *widget, g_object_unref (widget); } +static void +maybe_set_mnemonics_visible (GtkWindow *window) +{ + GList *devices, *d; + GdkDeviceManager *device_manager; + + device_manager = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (window))); + devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER); + + for (d = devices; d; d = d->next) + { + GdkDevice *dev = d->data; + + if (gdk_device_get_source (dev) == GDK_SOURCE_MOUSE) + { + GdkModifierType mask; + + gdk_device_get_state (dev, gtk_widget_get_window (GTK_WIDGET (window)), + NULL, &mask); + if (window->priv->mnemonic_modifier == (mask & gtk_accelerator_get_default_mod_mask ())) + { + _gtk_window_set_auto_mnemonics_visible (window); + break; + } + } + } + + g_list_free (devices); +} + static gint gtk_window_focus_in_event (GtkWidget *widget, GdkEventFocus *event) { GtkWindow *window = GTK_WINDOW (widget); + gboolean auto_mnemonics; /* It appears spurious focus in events can occur when * the window is hidden. So we'll just check to see if @@ -5844,8 +6208,13 @@ gtk_window_focus_in_event (GtkWidget *widget, { _gtk_window_set_has_toplevel_focus (window, TRUE); _gtk_window_set_is_active (window, TRUE); + + g_object_get (gtk_widget_get_settings (widget), + "gtk-auto-mnemonics", &auto_mnemonics, NULL); + if (auto_mnemonics) + maybe_set_mnemonics_visible (window); } - + return FALSE; } @@ -6056,60 +6425,6 @@ gtk_window_real_set_focus (GtkWindow *window, } } - -static void -gtk_window_get_preferred_width (GtkWidget *widget, - gint *minimum_size, - gint *natural_size) -{ - GtkWindow *window; - GtkWidget *child; - guint border_width; - - window = GTK_WINDOW (widget); - child = gtk_bin_get_child (GTK_BIN (window)); - - border_width = gtk_container_get_border_width (GTK_CONTAINER (window)); - *minimum_size = border_width * 2; - *natural_size = border_width * 2; - - if (child && gtk_widget_get_visible (child)) - { - gint child_min, child_nat; - gtk_widget_get_preferred_width (child, &child_min, &child_nat); - - *minimum_size += child_min; - *natural_size += child_nat; - } -} - -static void -gtk_window_get_preferred_height (GtkWidget *widget, - gint *minimum_size, - gint *natural_size) -{ - GtkWindow *window; - GtkWidget *child; - guint border_width; - - window = GTK_WINDOW (widget); - child = gtk_bin_get_child (GTK_BIN (window)); - - border_width = gtk_container_get_border_width (GTK_CONTAINER (window)); - *minimum_size = border_width * 2; - *natural_size = border_width * 2; - - if (child && gtk_widget_get_visible (child)) - { - gint child_min, child_nat; - gtk_widget_get_preferred_height (child, &child_min, &child_nat); - - *minimum_size += child_min; - *natural_size += child_nat; - } -} - - /** * _gtk_window_unset_focus_and_default: * @window: a #GtkWindow @@ -6161,8 +6476,8 @@ _gtk_window_unset_focus_and_default (GtkWindow *window, static void geometry_size_to_pixels (GdkGeometry *geometry, guint flags, - guint *width, - guint *height) + gint *width, + gint *height) { gint base_width = 0; gint base_height = 0; @@ -6198,29 +6513,21 @@ static void gtk_window_compute_configure_request_size (GtkWindow *window, GdkGeometry *geometry, guint flags, - guint *width, - guint *height) + gint *width, + gint *height) { GtkWindowPrivate *priv = window->priv; - GtkRequisition requisition; GtkWindowGeometryInfo *info; - GtkWidget *widget; /* Preconditions: * - we've done a size request */ - widget = GTK_WIDGET (window); - info = gtk_window_get_geometry_info (window, FALSE); if (priv->need_default_size) { - gtk_widget_get_preferred_size (widget, &requisition, NULL); - - /* Default to requisition */ - *width = requisition.width; - *height = requisition.height; + gtk_window_guess_default_size (window, width, height); /* If window is empty so requests 0, default to random nonzero size */ if (*width == 0 && *height == 0) @@ -6229,7 +6536,7 @@ gtk_window_compute_configure_request_size (GtkWindow *window, *height = 200; } - /* Override requisition with default size */ + /* Override with default size */ if (info) { @@ -6248,7 +6555,7 @@ gtk_window_compute_configure_request_size (GtkWindow *window, { GtkAllocation allocation; - gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (GTK_WIDGET (window), &allocation); /* Default to keeping current size */ *width = allocation.width; @@ -6340,13 +6647,13 @@ center_window_on_monitor (GtkWindow *window, 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); - + gdk_screen_get_monitor_workarea (gtk_window_check_screen (window), + monitor_num, &monitor); + *x = (monitor.width - w) / 2 + monitor.x; *y = (monitor.height - h) / 2 + monitor.y; @@ -6418,7 +6725,7 @@ gtk_window_compute_configure_request (GtkWindow *window, gtk_window_compute_hints (window, &new_geometry, &new_flags); gtk_window_compute_configure_request_size (window, &new_geometry, new_flags, - (guint *)&w, (guint *)&h); + &w, &h); gtk_window_constrain_size (window, &new_geometry, new_flags, @@ -6815,7 +7122,10 @@ gtk_window_move_resize (GtkWindow *window) &new_geometry, new_flags); - gtk_widget_get_allocation (widget, &allocation); + allocation.x = 0; + allocation.y = 0; + allocation.width = gdk_window_get_width (gdk_window); + allocation.height = gdk_window_get_height (gdk_window); /* handle resizing/moving and widget tree allocation */ @@ -6840,10 +7150,6 @@ gtk_window_move_resize (GtkWindow *window) set_grip_position (window); update_grip_visibility (window); - gdk_window_process_updates (gdk_window, TRUE); - - gdk_window_configure_finished (gdk_window); - /* If the configure request changed, it means that * we either: * 1) coincidentally changed hints or widget properties @@ -7144,7 +7450,7 @@ gtk_window_compute_hints (GtkWindow *window, extra_width = requisition.width - TEMPORARY_SIZE; extra_height = requisition.height - TEMPORARY_SIZE; - if (extra_width < 0 || extra_width < 0) + if (extra_width < 0 || extra_height < 0) { g_warning("Toplevel size doesn't seem to directly depend on the " "size of the geometry widget from gtk_window_set_geometry_hints(). " @@ -7188,6 +7494,10 @@ gtk_window_compute_hints (GtkWindow *window, } } + /* Please use a good size for unresizable widgets, not the minimum one. */ + if (!priv->resizable) + gtk_window_guess_default_size (window, &requisition.width, &requisition.height); + if (*new_flags & GDK_HINT_MIN_SIZE) { if (new_geometry->min_width < 0) @@ -7246,30 +7556,18 @@ gtk_window_draw (GtkWidget *widget, context = gtk_widget_get_style_context (widget); - gtk_style_context_save (context); - - if (!gtk_widget_get_app_paintable (widget)) + if (!gtk_widget_get_app_paintable (widget) && + gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) { - GtkStateFlags state; - - state = gtk_widget_get_state_flags (widget); - - if (gtk_window_has_toplevel_focus (GTK_WINDOW (widget))) - state |= GTK_STATE_FLAG_FOCUSED; - - gtk_style_context_set_state (context, state); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND); gtk_render_background (context, cr, 0, 0, gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)); } - gtk_style_context_restore (context); - if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw) ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr); - if (priv->grip_window != NULL && + if (priv->grip_window && gtk_cairo_should_draw_window (cr, priv->grip_window)) { GdkRectangle rect; @@ -7280,6 +7578,7 @@ gtk_window_draw (GtkWidget *widget, gtk_cairo_transform_to_window (cr, widget, priv->grip_window); gtk_window_get_resize_grip_area (GTK_WINDOW (widget), &rect); + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND); gtk_style_context_add_class (context, GTK_STYLE_CLASS_GRIP); gtk_style_context_set_junction_sides (context, get_grip_junction (widget)); gtk_render_handle (context, cr, 0, 0, rect.width, rect.height); @@ -7335,11 +7634,13 @@ void gtk_window_present_with_time (GtkWindow *window, guint32 timestamp) { + GtkWindowPrivate *priv; GtkWidget *widget; GdkWindow *gdk_window; g_return_if_fail (GTK_IS_WINDOW (window)); + priv = window->priv; widget = GTK_WIDGET (window); if (gtk_widget_get_visible (widget)) @@ -7354,19 +7655,23 @@ gtk_window_present_with_time (GtkWindow *window, if (timestamp == GDK_CURRENT_TIME) { #ifdef GDK_WINDOWING_X11 - GdkDisplay *display; + if (GDK_IS_X11_WINDOW(gdk_window)) + { + GdkDisplay *display; - display = gtk_widget_get_display (GTK_WIDGET (window)); - timestamp = gdk_x11_display_get_user_time (display); -#else - timestamp = gtk_get_current_event_time (); + display = gtk_widget_get_display (GTK_WIDGET (window)); + timestamp = gdk_x11_display_get_user_time (display); + } + else #endif + timestamp = gtk_get_current_event_time (); } gdk_window_focus (gdk_window, timestamp); } else { + priv->initial_timestamp = timestamp; gtk_widget_show (widget); } } @@ -7790,7 +8095,7 @@ gtk_window_set_resizable (GtkWindow *window, if (priv->resizable != resizable) { - priv->resizable = (resizable != FALSE); + priv->resizable = resizable; update_grip_visibility (window); @@ -7989,10 +8294,21 @@ gtk_window_set_screen (GtkWindow *window, if (screen != previous_screen) { if (previous_screen) - g_signal_handlers_disconnect_by_func (previous_screen, - gtk_window_on_composited_changed, window); + { + g_signal_handlers_disconnect_by_func (previous_screen, + gtk_window_on_composited_changed, window); +#ifdef GDK_WINDOWING_X11 + g_signal_handlers_disconnect_by_func (gtk_settings_get_for_screen (previous_screen), + gtk_window_on_theme_variant_changed, window); +#endif + } g_signal_connect (screen, "composited-changed", G_CALLBACK (gtk_window_on_composited_changed), window); +#ifdef GDK_WINDOWING_X11 + g_signal_connect (gtk_settings_get_for_screen (screen), + "notify::gtk-application-prefer-dark-theme", + G_CALLBACK (gtk_window_on_theme_variant_changed), window); +#endif _gtk_widget_propagate_screen_changed (widget, previous_screen); _gtk_widget_propagate_composited_changed (widget); @@ -8003,6 +8319,36 @@ gtk_window_set_screen (GtkWindow *window, gtk_widget_map (widget); } +static void +gtk_window_set_theme_variant (GtkWindow *window) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *gdk_window; + gboolean dark_theme_requested; + + g_object_get (gtk_settings_get_for_screen (window->priv->screen), + "gtk-application-prefer-dark-theme", &dark_theme_requested, + NULL); + + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + + if (GDK_IS_X11_WINDOW (gdk_window)) + gdk_x11_window_set_theme_variant (gdk_window, + dark_theme_requested ? "dark" : NULL); +#endif +} + +#ifdef GDK_WINDOWING_X11 +static void +gtk_window_on_theme_variant_changed (GtkSettings *settings, + GParamSpec *pspec, + GtkWindow *window) +{ + if (window->priv->type == GTK_WINDOW_TOPLEVEL) + gtk_window_set_theme_variant (window); +} +#endif + static void gtk_window_on_composited_changed (GdkScreen *screen, GtkWindow *window) @@ -8089,6 +8435,21 @@ gtk_window_has_toplevel_focus (GtkWindow *window) return window->priv->has_toplevel_focus; } + +/** + * SECTION:gtkwindowgroup + * @Short_description: Limit the effect of grabs + * @Title: GtkWindowGroup + * + * #GtkWindowGroup objects are referenced by each window in the group, + * so once you have added all windows to a #GtkWindowGroup, you can drop + * the initial reference to the window group with g_object_unref(). If the + * windows in the window group are subsequently destroyed, then they will + * be removed from the window group and drop their references on the window + * group; when all window have been removed, the window group will be + * freed. + */ + G_DEFINE_TYPE (GtkWindowGroup, gtk_window_group, G_TYPE_OBJECT) static void @@ -9110,8 +9471,8 @@ _gtk_window_set_is_active (GtkWindow *window, * in-process, parented GtkPlug) * * Internal function used by #GtkPlug when it gets parented/unparented by a - * #GtkSocket. This keeps the @window's #GTK_TOPLEVEL flag in sync with the - * global list of toplevel windows. + * #GtkSocket. This keeps the @window's #GTK_WINDOW_TOPLEVEL flag in sync + * with the global list of toplevel windows. */ void _gtk_window_set_is_toplevel (GtkWindow *window, @@ -9157,7 +9518,7 @@ _gtk_window_set_is_toplevel (GtkWindow *window, _gtk_widget_set_is_toplevel (widget, TRUE); /* When a window becomes toplevel after being embedded and anchored - * into another window we need to unset it's anchored flag so that + * into another window we need to unset its anchored flag so that * the hierarchy changed signal kicks in properly. */ _gtk_widget_set_anchored (widget, FALSE); @@ -9289,9 +9650,86 @@ gtk_window_set_mnemonics_visible (GtkWindow *window, g_object_notify (G_OBJECT (window), "mnemonics-visible"); } + if (priv->auto_mnemonics_timeout_id) + { + g_source_remove (priv->auto_mnemonics_timeout_id); + priv->auto_mnemonics_timeout_id = 0; + } + priv->mnemonics_visible_set = TRUE; } +static gboolean +set_auto_mnemonics_visible_cb (gpointer data) +{ + GtkWindow *window = data; + + gtk_window_set_mnemonics_visible (window, TRUE); + + window->priv->auto_mnemonics_timeout_id = 0; + + return FALSE; +} + +void +_gtk_window_set_auto_mnemonics_visible (GtkWindow *window) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (window->priv->auto_mnemonics_timeout_id) + return; + + window->priv->auto_mnemonics_timeout_id = + gdk_threads_add_timeout (AUTO_MNEMONICS_DELAY, set_auto_mnemonics_visible_cb, window); +} + +/** + * gtk_window_get_focus_visible: + * @window: a #GtkWindow + * + * Gets the value of the #GtkWindow:focus-visible property. + * + * Returns: %TRUE if 'focus rectangles' are supposed to be visible + * in this window. + * + * Since: 3.2 + */ +gboolean +gtk_window_get_focus_visible (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + return window->priv->focus_visible; +} + +/** + * gtk_window_set_focus_visible: + * @window: a #GtkWindow + * @setting: the new value + * + * Sets the #GtkWindow:focus-visible property. + * + * Since: 3.2 + */ +void +gtk_window_set_focus_visible (GtkWindow *window, + gboolean setting) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = window->priv; + + setting = setting != FALSE; + + if (priv->focus_visible != setting) + { + priv->focus_visible = setting; + g_object_notify (G_OBJECT (window), "focus-visible"); + } +} + void _gtk_window_get_wmclass (GtkWindow *window, gchar **wmclass_name, @@ -9309,7 +9747,7 @@ _gtk_window_get_wmclass (GtkWindow *window, * @setting: the new value * * Tells GTK+ whether to drop its extra reference to the window - * when gtk_window_destroy() is called. + * when gtk_widget_destroy() is called. * * This function is only exported for the benefit of language * bindings which may need to keep the window alive until their @@ -9326,3 +9764,21 @@ gtk_window_set_has_user_ref_count (GtkWindow *window, window->priv->has_user_ref_count = setting; } + +static void +ensure_state_flag_backdrop (GtkWidget *widget) +{ + GdkWindow *window; + gboolean window_focused = TRUE; + + window = gtk_widget_get_window (widget); + + window_focused = gdk_window_get_state (window) & GDK_WINDOW_STATE_FOCUSED; + + if (!window_focused) + gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_BACKDROP, FALSE); + else + gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_BACKDROP); + + gtk_widget_queue_draw (widget); +}