X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkwindow.c;h=98b5c86dd0c381245350f9ec6adcd31dc166330e;hb=f91c04e2846de010871ee21389eb926dd18e065e;hp=1e40a156523ce7f525b71fafb3441afd5160dea6;hpb=1d3f6b30b0100c96adbca9acb6c6cd49b18d2298;p=~andy%2Fgtk diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 1e40a1565..98b5c86dd 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -25,19 +25,18 @@ */ #include "config.h" + +#include "gtkwindow.h" + #include #include #include #include -#include "gdk/gdk.h" -#include "gdk/gdkkeysyms.h" - -#include "gtkintl.h" #include "gtkprivate.h" #include "gtkrc.h" -#include "gtkwindow.h" -#include "gtkwindow-decorate.h" +#include "gtkwindowprivate.h" +#include "gtkaccelgroupprivate.h" #include "gtkbindings.h" #include "gtkkeyhash.h" #include "gtkmain.h" @@ -48,7 +47,9 @@ #include "gtkmarshalers.h" #include "gtkplug.h" #include "gtkbuildable.h" -#include "gtksizerequest.h" +#include "gtkwidgetprivate.h" +#include "gtkintl.h" +#include "gtktypebuiltins.h" #ifdef GDK_WINDOWING_X11 #include "x11/gdkx.h" @@ -59,6 +60,16 @@ * @title: GtkWindow * @short_description: Toplevel which can contain other widgets * + * A GtkWindow is a toplevel window which can contain other widgets. + * Windows normally have decorations that are under the control + * of the windowing system and allow the user to manipulate the window + * (resize it, move it, close it,...). + * + * GTK+ also allows windows to have a resize grip (a small area in the lower + * right or left corner) which can be clicked to reszie the window. To + * control whether a window has a resize grip, use + * gtk_window_set_has_resize_grip(). + * * * GtkWindow as GtkBuildable * @@ -86,7 +97,6 @@ */ typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo; -typedef struct _GtkWindowGroupPrivate GtkWindowGroupPrivate; struct _GtkWindowPrivate { @@ -99,22 +109,21 @@ struct _GtkWindowPrivate GtkWindowGroup *group; GdkModifierType mnemonic_modifier; - GdkVisual *visual; - GdkWindow *frame; + GdkScreen *screen; GdkWindowTypeHint gdk_type_hint; + GtkApplication *application; + gdouble opacity; + GdkWindow *grip_window; + gchar *startup_id; gchar *title; gchar *wmclass_class; gchar *wmclass_name; gchar *wm_role; - guint frame_bottom; - guint frame_left; - guint frame_right; - guint frame_top; guint keys_changed_handler; guint16 configure_request_count; @@ -141,7 +150,6 @@ struct _GtkWindowPrivate guint gravity : 5; /* GdkGravity */ guint has_focus : 1; guint has_user_ref_count : 1; - guint has_frame : 1; guint has_toplevel_focus : 1; guint iconify_initially : 1; /* gtk_window_iconify() called before realization */ guint is_active : 1; @@ -158,9 +166,17 @@ struct _GtkWindowPrivate guint stick_initially : 1; guint transient_parent_group : 1; guint type : 4; /* GtkWindowType */ - guint type_hint : 3; /* GdkWindowTypeHint if the hint is one of the original eight. If not, then - * it contains GDK_WINDOW_TYPE_HINT_NORMAL */ + guint type_hint : 3; /* GdkWindowTypeHint if the hint is + * one of the original eight. If not, + * then it contains + * GDK_WINDOW_TYPE_HINT_NORMAL + */ guint urgent : 1; + guint has_resize_grip : 1; + guint resize_grip_visible : 1; /* don't use, just for "resize- + * grip-visible" notification + */ + }; enum { @@ -190,7 +206,6 @@ enum { PROP_ICON, PROP_ICON_NAME, PROP_SCREEN, - PROP_VISUAL, PROP_TYPE_HINT, PROP_SKIP_TASKBAR_HINT, PROP_SKIP_PAGER_HINT, @@ -202,7 +217,9 @@ enum { PROP_GRAVITY, PROP_TRANSIENT_FOR, PROP_OPACITY, - + PROP_HAS_RESIZE_GRIP, + PROP_RESIZE_GRIP_VISIBLE, + PROP_APPLICATION, /* Readonly properties */ PROP_IS_ACTIVE, PROP_HAS_TOPLEVEL_FOCUS, @@ -262,16 +279,19 @@ struct _GtkWindowGeometryInfo */ 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 + /* if true, default_width, height should be multiplied by the + * increments and affect the geometry widget only */ guint default_is_geometry : 1; + + /* if true, resize_width, height should be multiplied by the + * increments and affect the geometry widget only + */ + guint resize_is_geometry : 1; GtkWindowLastGeometryInfo last; }; -#define GTK_WINDOW_GROUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_WINDOW_GROUP, GtkWindowGroupPrivate)) struct _GtkDeviceGrabInfo { @@ -282,12 +302,13 @@ struct _GtkDeviceGrabInfo struct _GtkWindowGroupPrivate { + GSList *grabs; GSList *device_grabs; }; 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_destroy (GtkWidget *widget); static void gtk_window_show (GtkWidget *widget); static void gtk_window_hide (GtkWidget *widget); static void gtk_window_map (GtkWidget *widget); @@ -296,18 +317,16 @@ static void gtk_window_realize (GtkWidget *widget); static void gtk_window_unrealize (GtkWidget *widget); static void gtk_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -static gint gtk_window_event (GtkWidget *widget, - GdkEvent *event); static gboolean gtk_window_map_event (GtkWidget *widget, GdkEventAny *event); -static gboolean gtk_window_frame_event (GtkWindow *window, - GdkEvent *event); static gint gtk_window_configure_event (GtkWidget *widget, GdkEventConfigure *event); static gint gtk_window_key_press_event (GtkWidget *widget, GdkEventKey *event); static gint gtk_window_key_release_event (GtkWidget *widget, GdkEventKey *event); +static gint gtk_window_button_press_event (GtkWidget *widget, + GdkEventButton *event); static gint gtk_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_window_leave_notify_event (GtkWidget *widget, @@ -316,18 +335,23 @@ static gint gtk_window_focus_in_event (GtkWidget *widget, GdkEventFocus *event); static gint gtk_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event); -static gint gtk_window_client_event (GtkWidget *widget, - GdkEventClient *event); +static void gtk_window_style_updated (GtkWidget *widget); +static gboolean gtk_window_state_event (GtkWidget *widget, + GdkEventWindowState *event); static void gtk_window_check_resize (GtkContainer *container); static gint gtk_window_focus (GtkWidget *widget, GtkDirectionType direction); +static void gtk_window_move_focus (GtkWidget *widget, + GtkDirectionType dir); static void gtk_window_real_set_focus (GtkWindow *window, GtkWidget *focus); +static void gtk_window_direction_changed (GtkWidget *widget, + GtkTextDirection prev_dir); +static void gtk_window_state_changed (GtkWidget *widget, + GtkStateType previous_state); 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 gint gtk_window_draw (GtkWidget *widget, cairo_t *cr); @@ -380,6 +404,9 @@ static GList *icon_list_from_theme (GtkWidget *widget, const gchar *name); static void gtk_window_realize_icon (GtkWindow *window); static void gtk_window_unrealize_icon (GtkWindow *window); +static void resize_grip_create_window (GtkWindow *window); +static void resize_grip_destroy_window (GtkWindow *window); +static void update_grip_visibility (GtkWindow *window); static void gtk_window_notify_keys_changed (GtkWindow *window); static GtkKeyHash *gtk_window_get_key_hash (GtkWindow *window); @@ -432,19 +459,16 @@ static void gtk_window_buildable_custom_finished (GtkBuildable *buildable, gpointer user_data); -static void gtk_window_size_request_init (GtkSizeRequestIface *iface); -static void gtk_window_get_width (GtkSizeRequest *widget, +static void gtk_window_get_preferred_width (GtkWidget *widget, gint *minimum_size, gint *natural_size); -static void gtk_window_get_height (GtkSizeRequest *widget, +static void gtk_window_get_preferred_height (GtkWidget *widget, gint *minimum_size, gint *natural_size); G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gtk_window_buildable_interface_init) - G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST, - gtk_window_size_request_init)) + gtk_window_buildable_interface_init)) static void add_tab_bindings (GtkBindingSet *binding_set, @@ -494,9 +518,10 @@ extract_time_from_startup_id (const gchar* startup_id) /* Skip past the "_TIME" part */ timestr += 5; + end = NULL; errno = 0; - timestamp = strtoul (timestr, &end, 0); - if (end != timestr && errno == 0) + timestamp = g_ascii_strtoull (timestr, &end, 0); + if (errno == 0 && end != timestr) retval = timestamp; } @@ -513,12 +538,10 @@ static void gtk_window_class_init (GtkWindowClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; GtkBindingSet *binding_set; - - object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; container_class = (GtkContainerClass*) klass; @@ -532,9 +555,8 @@ gtk_window_class_init (GtkWindowClass *klass) gobject_class->set_property = gtk_window_set_property; gobject_class->get_property = gtk_window_get_property; - - object_class->destroy = gtk_window_destroy; + widget_class->destroy = gtk_window_destroy; widget_class->show = gtk_window_show; widget_class->hide = gtk_window_hide; widget_class->map = gtk_window_map; @@ -549,19 +571,24 @@ gtk_window_class_init (GtkWindowClass *klass) widget_class->enter_notify_event = gtk_window_enter_notify_event; widget_class->leave_notify_event = gtk_window_leave_notify_event; widget_class->focus_in_event = gtk_window_focus_in_event; + widget_class->button_press_event = gtk_window_button_press_event; widget_class->focus_out_event = gtk_window_focus_out_event; - widget_class->client_event = gtk_window_client_event; 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; + widget_class->style_updated = gtk_window_style_updated; container_class->check_resize = gtk_window_check_resize; klass->set_focus = gtk_window_real_set_focus; - klass->frame_event = gtk_window_frame_event; 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 = gtk_window_keys_changed; g_type_class_add_private (gobject_class, sizeof (GtkWindowPrivate)); @@ -701,20 +728,6 @@ gtk_window_class_init (GtkWindowClass *klass) GDK_TYPE_SCREEN, GTK_PARAM_READWRITE)); - /** - * GtkWindow:visual: - * - * Specifies the visual used to create the window with. See gtk_window_set_visual() - * for more details. - */ - g_object_class_install_property (gobject_class, - PROP_VISUAL, - g_param_spec_object ("visual", - P_("Visual"), - P_("The visual this window is created from"), - GDK_TYPE_VISUAL, - GTK_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_IS_ACTIVE, g_param_spec_boolean ("is-active", @@ -824,6 +837,41 @@ gtk_window_class_init (GtkWindowClass *klass) TRUE, GTK_PARAM_READWRITE)); + /** + * GtkWindow:has-resize-grip + * + * Whether the window has a corner resize grip. + * + * Note that the resize grip is only shown if the window is + * actually resizable and not maximized. Use + * #GtkWindow:resize-grip-visible to find out if the resize + * grip is currently shown. + * + * Since: 3.0 + */ + g_object_class_install_property (gobject_class, + PROP_HAS_RESIZE_GRIP, + g_param_spec_boolean ("has-resize-grip", + P_("Resize grip"), + P_("Specifies whether the window should have a resize grip"), + TRUE, + GTK_PARAM_READWRITE)); + + /** + * GtkWindow:resize-grip-visible: + * + * Whether a corner resize grip is currently shown. + * + * Since: 3.0 + */ + g_object_class_install_property (gobject_class, + PROP_RESIZE_GRIP_VISIBLE, + g_param_spec_boolean ("resize-grip-visible", + P_("Resize grip is visible"), + P_("Specifies whether the window's resize grip is visible."), + FALSE, + GTK_PARAM_READABLE)); + /** * GtkWindow:gravity: @@ -877,6 +925,44 @@ gtk_window_class_init (GtkWindowClass *klass) 1.0, GTK_PARAM_READWRITE)); + /* Style properties. + */ + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("resize-grip-width", + P_("Width of resize grip"), + P_("Width of resize grip"), + 0, G_MAXINT, 16, GTK_PARAM_READWRITE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("resize-grip-height", + P_("Height of resize grip"), + P_("Height of resize grip"), + 0, G_MAXINT, 16, GTK_PARAM_READWRITE)); + + + /** + * GtkWindow:application: + * + * The #GtkApplication associated with the window. + * + * The application will be kept alive for at least as long as it + * has any windows associated with it (see g_application_hold() + * for a way to keep it alive without windows). + * + * Normally, the connection between the application and the window + * will remain until the window is destroyed, but you can explicitly + * remove it by setting the ::application property to %NULL. + * + * Since: 3.0 + */ + g_object_class_install_property (gobject_class, + PROP_APPLICATION, + g_param_spec_object ("application", + P_("GtkApplication"), + P_("The GtkApplication for the window"), + GTK_TYPE_APPLICATION, + GTK_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + window_signals[SET_FOCUS] = g_signal_new (I_("set-focus"), G_TYPE_FROM_CLASS (gobject_class), @@ -886,16 +972,6 @@ gtk_window_class_init (GtkWindowClass *klass) _gtk_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - - window_signals[FRAME_EVENT] = - g_signal_new (I_("frame-event"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GtkWindowClass, frame_event), - _gtk_boolean_handled_accumulator, NULL, - _gtk_marshal_BOOLEAN__BOXED, - G_TYPE_BOOLEAN, 1, - GDK_TYPE_EVENT); /** * GtkWindow::activate-focus: @@ -994,7 +1070,7 @@ gtk_window_init (GtkWindow *window) gtk_widget_set_has_window (GTK_WIDGET (window), TRUE); _gtk_widget_set_is_toplevel (GTK_WIDGET (window), TRUE); - GTK_PRIVATE_SET_FLAG (window, GTK_ANCHORED); + _gtk_widget_set_anchored (GTK_WIDGET (window), TRUE); gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE); @@ -1013,17 +1089,11 @@ gtk_window_init (GtkWindow *window) priv->need_default_size = TRUE; priv->need_default_position = TRUE; priv->modal = FALSE; - priv->frame = NULL; - priv->has_frame = FALSE; - priv->frame_left = 0; - priv->frame_right = 0; - priv->frame_top = 0; - priv->frame_bottom = 0; priv->gdk_type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; priv->gravity = GDK_GRAVITY_NORTH_WEST; priv->decorated = TRUE; priv->mnemonic_modifier = GDK_MOD1_MASK; - priv->visual = gdk_screen_get_system_visual (gdk_screen_get_default ()); + priv->screen = gdk_screen_get_default (); priv->accept_focus = TRUE; priv->focus_on_map = TRUE; @@ -1031,16 +1101,16 @@ gtk_window_init (GtkWindow *window) priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL; priv->opacity = 1.0; priv->startup_id = NULL; + priv->has_resize_grip = TRUE; priv->mnemonics_visible = TRUE; g_object_ref_sink (window); priv->has_user_ref_count = TRUE; toplevel_list = g_slist_prepend (toplevel_list, window); - gtk_decorated_window_init (window); - - g_signal_connect (gdk_screen_get_default (), "composited-changed", - G_CALLBACK (gtk_window_on_composited_changed), window); + if (priv->screen) + g_signal_connect (priv->screen, "composited-changed", + G_CALLBACK (gtk_window_on_composited_changed), window); } static void @@ -1051,7 +1121,7 @@ gtk_window_set_property (GObject *object, { GtkWindow *window = GTK_WINDOW (object); GtkWindowPrivate *priv = window->priv; - + switch (prop_id) { case PROP_TYPE: @@ -1065,10 +1135,9 @@ gtk_window_set_property (GObject *object, break; case PROP_STARTUP_ID: gtk_window_set_startup_id (window, g_value_get_string (value)); - break; + break; case PROP_RESIZABLE: - priv->resizable = g_value_get_boolean (value); - gtk_widget_queue_resize (GTK_WIDGET (window)); + gtk_window_set_resizable (window, g_value_get_boolean (value)); break; case PROP_MODAL: gtk_window_set_modal (window, g_value_get_boolean (value)); @@ -1099,9 +1168,6 @@ gtk_window_set_property (GObject *object, case PROP_SCREEN: gtk_window_set_screen (window, g_value_get_object (value)); break; - case PROP_VISUAL: - gtk_window_set_visual (window, g_value_get_object (value)); - break; case PROP_TYPE_HINT: gtk_window_set_type_hint (window, g_value_get_enum (value)); @@ -1141,6 +1207,12 @@ gtk_window_set_property (GObject *object, case PROP_OPACITY: gtk_window_set_opacity (window, g_value_get_double (value)); break; + case PROP_HAS_RESIZE_GRIP: + gtk_window_set_has_resize_grip (window, g_value_get_boolean (value)); + break; + case PROP_APPLICATION: + gtk_window_set_application (window, g_value_get_object (value)); + break; case PROP_MNEMONICS_VISIBLE: gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value)); break; @@ -1204,10 +1276,7 @@ gtk_window_get_property (GObject *object, g_value_set_string (value, gtk_window_get_icon_name (window)); break; case PROP_SCREEN: - g_value_set_object (value, gdk_visual_get_screen (priv->visual)); - break; - case PROP_VISUAL: - g_value_set_object (value, priv->visual); + g_value_set_object (value, priv->screen); break; case PROP_IS_ACTIVE: g_value_set_boolean (value, priv->is_active); @@ -1253,6 +1322,15 @@ gtk_window_get_property (GObject *object, case PROP_OPACITY: g_value_set_double (value, gtk_window_get_opacity (window)); break; + case PROP_HAS_RESIZE_GRIP: + g_value_set_boolean (value, priv->has_resize_grip); + break; + case PROP_RESIZE_GRIP_VISIBLE: + g_value_set_boolean (value, gtk_window_resize_grip_is_visible (window)); + break; + case PROP_APPLICATION: + g_value_set_object (value, gtk_window_get_application (window)); + break; case PROP_MNEMONICS_VISIBLE: g_value_set_boolean (value, priv->mnemonics_visible); break; @@ -1478,8 +1556,6 @@ gtk_window_set_title (GtkWindow *window, { gdk_window_set_title (gtk_widget_get_window (widget), priv->title); - - gtk_decorated_window_set_title (window, title); } g_object_notify (G_OBJECT (window), "title"); @@ -2216,50 +2292,6 @@ gtk_window_list_toplevels (void) return list; } -void -gtk_window_add_embedded_xid (GtkWindow *window, GdkNativeWindow xid) -{ - GList *embedded_windows; - - g_return_if_fail (GTK_IS_WINDOW (window)); - - embedded_windows = g_object_get_qdata (G_OBJECT (window), quark_gtk_embedded); - if (embedded_windows) - g_object_steal_qdata (G_OBJECT (window), quark_gtk_embedded); - embedded_windows = g_list_prepend (embedded_windows, - GUINT_TO_POINTER (xid)); - - g_object_set_qdata_full (G_OBJECT (window), quark_gtk_embedded, - embedded_windows, - embedded_windows ? - (GDestroyNotify) g_list_free : NULL); -} - -void -gtk_window_remove_embedded_xid (GtkWindow *window, GdkNativeWindow xid) -{ - GList *embedded_windows; - GList *node; - - g_return_if_fail (GTK_IS_WINDOW (window)); - - embedded_windows = g_object_get_qdata (G_OBJECT (window), quark_gtk_embedded); - if (embedded_windows) - g_object_steal_qdata (G_OBJECT (window), quark_gtk_embedded); - - node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid)); - if (node) - { - embedded_windows = g_list_remove_link (embedded_windows, node); - g_list_free_1 (node); - } - - g_object_set_qdata_full (G_OBJECT (window), quark_gtk_embedded, - embedded_windows, - embedded_windows ? - (GDestroyNotify) g_list_free : NULL); -} - static void gtk_window_dispose (GObject *object) { @@ -2327,7 +2359,7 @@ gtk_window_transient_parent_screen_changed (GtkWindow *parent, GParamSpec *pspec, GtkWindow *window) { - gtk_window_set_screen (window, gtk_window_get_screen (parent)); + gtk_window_set_screen (window, parent->priv->screen); } static void @@ -2421,8 +2453,8 @@ gtk_window_set_transient_for (GtkWindow *window, g_signal_connect (parent, "notify::screen", G_CALLBACK (gtk_window_transient_parent_screen_changed), window); - - gtk_window_set_screen (window, gtk_window_get_screen (parent)); + + gtk_window_set_screen (window, parent->priv->screen); if (priv->destroy_with_parent) connect_parent_destroyed (window); @@ -2517,6 +2549,78 @@ gtk_window_get_opacity (GtkWindow *window) return window->priv->opacity; } +/** + * gtk_window_get_application: + * @window: a #GtkWindow + * + * Gets the #GtkApplication associated with the window (if any). + * + * Return value: (transfer none): a #GtkApplication, or %NULL + * + * Since: 3.0 + **/ +GtkApplication * +gtk_window_get_application (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); + + return window->priv->application; +} + +static void +gtk_window_release_application (GtkWindow *window) +{ + if (window->priv->application) + { + GtkApplication *application; + + /* steal reference into temp variable */ + application = window->priv->application; + window->priv->application = NULL; + + gtk_application_remove_window (application, window); + g_object_unref (application); + } +} + +/** + * gtk_window_set_application: + * @window: a #GtkWindow + * @application: (allow-none): a #GtkApplication, or %NULL + * + * Sets or unsets the #GtkApplication associated with the window. + * + * The application will be kept alive for at least as long as the window + * is open. + * + * Since: 3.0 + **/ +void +gtk_window_set_application (GtkWindow *window, + GtkApplication *application) +{ + GtkWindowPrivate *priv; + + g_return_if_fail (GTK_IS_WINDOW (window)); + + priv = window->priv; + if (priv->application != application) + { + gtk_window_release_application (window); + + priv->application = application; + + if (priv->application != NULL) + { + g_object_ref (priv->application); + + gtk_application_add_window (priv->application, window); + } + + g_object_notify (G_OBJECT (window), "application"); + } +} + /** * gtk_window_set_type_hint: * @window: a #GtkWindow @@ -2957,7 +3061,7 @@ gtk_window_set_geometry_hints (GtkWindow *window, { gtk_window_set_gravity (window, geometry->win_gravity); } - + gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); } @@ -2973,7 +3077,7 @@ gtk_window_set_geometry_hints (GtkWindow *window, * 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(). + * 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. @@ -3233,6 +3337,8 @@ gtk_window_realize_icon (GtkWindow *window) } info->realized = TRUE; + + gdk_window_set_icon_list (gtk_widget_get_window (widget), icon_list); if (info->using_themed_icon) { @@ -3277,7 +3383,7 @@ gtk_window_unrealize_icon (GtkWindow *window) /** * gtk_window_set_icon_list: * @window: a #GtkWindow - * @list: (element-type GdkPixbuf) (transfer container): list of #GdkPixbuf + * @list: (element-type GdkPixbuf): list of #GdkPixbuf * * Sets up the icon representing a #GtkWindow. The icon is used when * the window is minimized (also known as iconified). Some window @@ -3537,7 +3643,7 @@ load_pixbuf_verbosely (const char *filename, /** * gtk_window_set_icon_from_file: * @window: a #GtkWindow - * @filename: location of icon file + * @filename: (type filename): location of icon file * @err: (allow-none): location to store error, or %NULL. * * Sets the icon for @window. @@ -3715,7 +3821,7 @@ gtk_window_get_default_icon_name (void) /** * gtk_window_set_default_icon_from_file: - * @filename: location of icon file + * @filename: (type filename): location of icon file * @err: (allow-none): location to store error, or %NULL. * * Sets an icon to be used as fallback for windows that haven't @@ -3856,6 +3962,30 @@ gtk_window_set_default_size (GtkWindow *window, gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE); } +/** + * gtk_window_set_default_geometry: + * @window: a #GtkWindow + * @width: width in resize increments, or -1 to unset the default width + * @height: height in resize increments, or -1 to unset the default height + * + * Like gtk_window_set_default_size(), but @width and @height are interpreted + * in terms of the base size and increment set with + * gtk_window_set_geometry_hints. + * + * Since: 3.0 + */ +void +gtk_window_set_default_geometry (GtkWindow *window, + gint width, + gint height) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, TRUE); +} + /** * gtk_window_get_default_size: * @window: a #GtkWindow @@ -3920,6 +4050,39 @@ gtk_window_resize (GtkWindow *window, info->resize_width = width; info->resize_height = height; + info->resize_is_geometry = FALSE; + + gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); +} + +/** + * gtk_window_resize_to_geometry: + * @window: a #GtkWindow + * @width: width in resize increments to resize the window to + * @height: height in resize increments to resize the window to + * + * Like gtk_window_resize(), but @width and @height are interpreted + * in terms of the base size and increment set with + * gtk_window_set_geometry_hints. + * + * Since: 3.0 + */ +void +gtk_window_resize_to_geometry (GtkWindow *window, + gint width, + gint height) +{ + GtkWindowGeometryInfo *info; + + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (width > 0); + g_return_if_fail (height > 0); + + info = gtk_window_get_geometry_info (window, TRUE); + + info->resize_width = width; + info->resize_height = height; + info->resize_is_geometry = TRUE; gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); } @@ -3990,8 +4153,8 @@ gtk_window_get_size (GtkWindow *window, if (gtk_widget_get_mapped (GTK_WIDGET (window))) { - gdk_drawable_get_size (gtk_widget_get_window (GTK_WIDGET (window)), - &w, &h); + w = gdk_window_get_width (gtk_widget_get_window (GTK_WIDGET (window))); + h = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (window))); } else { @@ -4046,9 +4209,9 @@ gtk_window_get_size (GtkWindow *window, * gdk_screen_height () - window_height) (note that this * example does not take multi-head scenarios into account). * - * The Extended Window Manager Hints specification at - * http://www.freedesktop.org/Standards/wm-spec has a + * http://www.freedesktop.org/Standards/wm-spec has a * nice table of gravities in the "implementation notes" section. * * The gtk_window_get_position() documentation may also be relevant. @@ -4058,17 +4221,15 @@ gtk_window_move (GtkWindow *window, gint x, gint y) { - GtkWindowPrivate *priv; GtkWindowGeometryInfo *info; GtkWidget *widget; - + g_return_if_fail (GTK_IS_WINDOW (window)); - priv = window->priv; widget = GTK_WIDGET (window); info = gtk_window_get_geometry_info (window, TRUE); - + if (gtk_widget_get_mapped (widget)) { GtkAllocation allocation; @@ -4091,7 +4252,7 @@ gtk_window_move (GtkWindow *window, gtk_window_constrain_position (window, allocation.width, allocation.height, &x, &y); - + /* Note that this request doesn't go through our standard request * framework, e.g. doesn't increment configure_request_count, * doesn't set info->last, etc.; that's because @@ -4102,15 +4263,7 @@ gtk_window_move (GtkWindow *window, * the same as the position being changed by the window * manager. */ - - /* FIXME are we handling gravity properly for framed windows? */ - if (priv->frame) - gdk_window_move (priv->frame, - x - priv->frame_left, - y - priv->frame_top); - else - gdk_window_move (gtk_widget_get_window (GTK_WIDGET (window)), - x, y); + gdk_window_move (gtk_widget_get_window (GTK_WIDGET (window)), x, y); } else { @@ -4215,10 +4368,7 @@ gtk_window_get_position (GtkWindow *window, if (gtk_widget_get_mapped (widget)) { - if (priv->frame) - gdk_window_get_frame_extents (priv->frame, &frame_extents); - else - gdk_window_get_frame_extents (gdk_window, &frame_extents); + gdk_window_get_frame_extents (gdk_window, &frame_extents); x = frame_extents.x; y = frame_extents.y; gtk_window_get_size (window, &w, &h); @@ -4227,7 +4377,7 @@ gtk_window_get_position (GtkWindow *window, { /* We just say the frame has 0 size on all sides. * Not sure what else to do. - */ + */ gtk_window_compute_configure_request (window, &frame_extents, NULL, NULL); @@ -4312,11 +4462,13 @@ gtk_window_reshow_with_initial_size (GtkWindow *window) } static void -gtk_window_destroy (GtkObject *object) +gtk_window_destroy (GtkWidget *widget) { - GtkWindow *window = GTK_WINDOW (object); + GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = window->priv; + gtk_window_release_application (window); + toplevel_list = g_slist_remove (toplevel_list, window); if (priv->transient_parent) @@ -4324,7 +4476,7 @@ gtk_window_destroy (GtkObject *object) /* frees the icons */ gtk_window_set_icon_list (window, NULL); - + if (priv->has_user_ref_count) { priv->has_user_ref_count = FALSE; @@ -4336,7 +4488,7 @@ gtk_window_destroy (GtkObject *object) gtk_window_free_key_hash (window); - GTK_OBJECT_CLASS (gtk_window_parent_class)->destroy (object); + GTK_WIDGET_CLASS (gtk_window_parent_class)->destroy (widget); } static void @@ -4350,6 +4502,7 @@ gtk_window_finalize (GObject *object) g_free (priv->wmclass_name); g_free (priv->wmclass_class); g_free (priv->wm_role); + gtk_window_release_application (window); mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE); if (mnemonic_hash) @@ -4370,8 +4523,8 @@ gtk_window_finalize (GObject *object) priv->keys_changed_handler = 0; } - if (priv->visual) - g_signal_handlers_disconnect_by_func (gdk_visual_get_screen (priv->visual), + if (priv->screen) + g_signal_handlers_disconnect_by_func (priv->screen, gtk_window_on_composited_changed, window); g_free (priv->startup_id); @@ -4386,8 +4539,15 @@ gtk_window_show (GtkWidget *widget) GtkWindowPrivate *priv = window->priv; GtkContainer *container = GTK_CONTAINER (window); gboolean need_resize; + gboolean is_plug; + + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + { + GTK_WIDGET_CLASS (gtk_window_parent_class)->show (widget); + return; + } - GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + _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); @@ -4433,11 +4593,6 @@ gtk_window_show (GtkWidget *widget) was_realized = TRUE; } - /* Must be done after the windows are realized, - * so that the decorations can be read - */ - gtk_decorated_window_calculate_frame_size (window); - /* We only send configure request if we didn't just finish * creating the window; if we just created the window * then we created it with widget->allocation anyhow. @@ -4456,8 +4611,13 @@ gtk_window_show (GtkWidget *widget) /* Try to make sure that we have some focused widget */ - if (!priv->focus_widget && !GTK_IS_PLUG (window)) - gtk_window_move_focus (window, GTK_DIR_TAB_FORWARD); +#ifdef GDK_WINDOWING_X11 + is_plug = GTK_IS_PLUG (window); +#else + is_plug = FALSE; +#endif + if (!priv->focus_widget && !is_plug) + gtk_window_move_focus (widget, GTK_DIR_TAB_FORWARD); if (priv->modal) gtk_grab_add (widget); @@ -4469,7 +4629,13 @@ gtk_window_hide (GtkWidget *widget) GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = window->priv; - GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + { + GTK_WIDGET_CLASS (gtk_window_parent_class)->hide (widget); + return; + } + + _gtk_widget_set_visible_flag (widget, FALSE); gtk_widget_unmap (widget); if (priv->modal) @@ -4488,6 +4654,12 @@ gtk_window_map (GtkWidget *widget) gdk_window = gtk_widget_get_window (widget); + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + { + GTK_WIDGET_CLASS (gtk_window_parent_class)->map (widget); + return; + } + gtk_widget_set_mapped (widget, TRUE); child = gtk_bin_get_child (&(window->bin)); @@ -4496,10 +4668,7 @@ gtk_window_map (GtkWidget *widget) !gtk_widget_get_mapped (child)) gtk_widget_map (child); - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gdk_window; + toplevel = gdk_window; if (priv->maximize_initially) gdk_window_maximize (toplevel); @@ -4542,8 +4711,8 @@ gtk_window_map (GtkWidget *widget) gdk_window_show (gdk_window); - if (priv->frame) - gdk_window_show (priv->frame); + if (priv->grip_window) + gdk_window_show (priv->grip_window); if (!disable_startup_notification) { @@ -4596,17 +4765,21 @@ gtk_window_unmap (GtkWidget *widget) { GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = window->priv; - GtkWindowGeometryInfo *info; + GtkWidget *child; + GtkWindowGeometryInfo *info; GdkWindow *gdk_window; GdkWindowState state; + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + { + GTK_WIDGET_CLASS (gtk_window_parent_class)->unmap (widget); + return; + } + gdk_window = gtk_widget_get_window (widget); gtk_widget_set_mapped (widget, FALSE); - if (priv->frame) - gdk_window_withdraw (priv->frame); - else - gdk_window_withdraw (gdk_window); + gdk_window_withdraw (gdk_window); priv->configure_request_count = 0; priv->configure_notify_received = FALSE; @@ -4630,6 +4803,10 @@ gtk_window_unmap (GtkWidget *widget) priv->stick_initially = (state & GDK_WINDOW_STATE_STICKY) != 0; priv->above_initially = (state & GDK_WINDOW_STATE_ABOVE) != 0; priv->below_initially = (state & GDK_WINDOW_STATE_BELOW) != 0; + + child = gtk_bin_get_child (&(window->bin)); + if (child) + gtk_widget_unmap (child); } static void @@ -4637,18 +4814,50 @@ gtk_window_realize (GtkWidget *widget) { GtkAllocation allocation; GtkWindow *window; - GtkStyle *style; GdkWindow *parent_window; GdkWindow *gdk_window; GdkWindowAttr attributes; gint attributes_mask; GtkWindowPrivate *priv; + GtkStyleContext *context; window = GTK_WINDOW (widget); priv = window->priv; gtk_widget_get_allocation (widget, &allocation); + if (gtk_widget_get_parent_window (widget)) + { + gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT); + + gtk_widget_set_realized (widget, TRUE); + + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK; + + attributes.visual = gtk_widget_get_visual (widget); + attributes.wclass = GDK_INPUT_OUTPUT; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + + 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_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window); + + gdk_window_enable_synchronized_configure (gdk_window); + return; + } + + gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE); + /* ensure widget tree is properly size allocated */ if (allocation.x == -1 && allocation.y == -1 && @@ -4656,10 +4865,13 @@ gtk_window_realize (GtkWidget *widget) allocation.height == 1) { GtkRequisition requisition; - GtkAllocation allocation = { 0, 0, 200, 200 }; - gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), - &requisition, NULL); + 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) { /* non-empty window */ @@ -4687,57 +4899,15 @@ gtk_window_realize (GtkWidget *widget) g_warning (G_STRLOC": Unknown window type %d!", priv->type); break; } - + attributes.title = priv->title; attributes.wmclass_name = priv->wmclass_name; attributes.wmclass_class = priv->wmclass_class; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); - if (priv->has_frame) - { - gtk_widget_get_allocation (widget, &allocation); - attributes.width = allocation.width + priv->frame_left + priv->frame_right; - attributes.height = allocation.height + priv->frame_top + priv->frame_bottom; - attributes.event_mask = (GDK_EXPOSURE_MASK | - GDK_KEY_PRESS_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_FOCUS_CHANGE_MASK | - GDK_STRUCTURE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK); - - attributes_mask = GDK_WA_VISUAL; - - priv->frame = gdk_window_new (gtk_widget_get_root_window (widget), - &attributes, attributes_mask); - - if (priv->opacity_set) - gdk_window_set_opacity (priv->frame, priv->opacity); - - gdk_window_set_user_data (priv->frame, widget); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = priv->frame_left; - attributes.y = priv->frame_top; - - attributes_mask = GDK_WA_X | GDK_WA_Y; - - parent_window = priv->frame; - - g_signal_connect (window, - "event", - G_CALLBACK (gtk_window_event), - NULL); - } - else - { - attributes_mask = 0; - parent_window = gtk_widget_get_root_window (widget); - } + attributes_mask = 0; + parent_window = gtk_widget_get_root_window (widget); gtk_widget_get_allocation (widget, &allocation); attributes.width = allocation.width; @@ -4759,18 +4929,16 @@ gtk_window_realize (GtkWidget *widget) gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask); gtk_widget_set_window (widget, gdk_window); - if (!priv->has_frame && priv->opacity_set) + 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_style_attach (widget); - style = gtk_widget_get_style (widget); - gtk_style_set_background (style, gdk_window, GTK_STATE_NORMAL); - if (priv->frame) - gtk_style_set_background (style, priv->frame, GTK_STATE_NORMAL); + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_background (context, gdk_window); + if (priv->transient_parent && gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent))) @@ -4779,47 +4947,50 @@ gtk_window_realize (GtkWidget *widget) if (priv->wm_role) gdk_window_set_role (gdk_window, priv->wm_role); - + if (!priv->decorated) gdk_window_set_decorations (gdk_window, 0); - + if (!priv->deletable) gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE); - + if (gtk_window_get_skip_pager_hint (window)) gdk_window_set_skip_pager_hint (gdk_window, TRUE); - + if (gtk_window_get_skip_taskbar_hint (window)) gdk_window_set_skip_taskbar_hint (gdk_window, TRUE); - + if (gtk_window_get_accept_focus (window)) gdk_window_set_accept_focus (gdk_window, TRUE); else gdk_window_set_accept_focus (gdk_window, FALSE); - + if (gtk_window_get_focus_on_map (window)) gdk_window_set_focus_on_map (gdk_window, TRUE); else gdk_window_set_focus_on_map (gdk_window, FALSE); - + if (priv->modal) 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); + 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); + gdk_window_set_startup_id (gdk_window, priv->startup_id); } - + /* Icons */ gtk_window_realize_icon (window); + + if (priv->has_resize_grip) + resize_grip_create_window (window); } static void @@ -4849,110 +5020,214 @@ gtk_window_unrealize (GtkWidget *widget) info->last.flags = 0; } - if (priv->frame) - { - gdk_window_set_user_data (priv->frame, NULL); - gdk_window_destroy (priv->frame); - priv->frame = NULL; - } - /* Icons */ gtk_window_unrealize_icon (window); + if (priv->grip_window != NULL) + resize_grip_destroy_window (window); + GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget); } +static GtkJunctionSides +get_grip_junction (GtkWidget *widget) +{ + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + return GTK_JUNCTION_CORNER_BOTTOMRIGHT; + else + return GTK_JUNCTION_CORNER_BOTTOMLEFT; +} + +static gboolean +get_drag_edge (GtkWidget *widget, + GdkWindowEdge *edge) +{ + GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv; + gboolean hresizable; + gboolean vresizable; + GtkTextDirection dir; + GtkWindowGeometryInfo *info; + + hresizable = TRUE; + vresizable = TRUE; + + info = priv->geometry_info; + if (info) + { + GdkWindowHints flags = info->last.flags; + GdkGeometry *geometry = &info->last.geometry; + + if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE)) + { + hresizable = geometry->min_width < geometry->max_width; + vresizable = geometry->min_height < geometry->max_height; + } + } + + dir = gtk_widget_get_direction (widget); + + if (hresizable && vresizable) + *edge = dir == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_SOUTH_EAST : GDK_WINDOW_EDGE_SOUTH_WEST; + else if (hresizable) + *edge = dir == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_EAST : GDK_WINDOW_EDGE_WEST; + else if (vresizable) + *edge = GDK_WINDOW_EDGE_SOUTH; + else + return FALSE; + + return TRUE; +} + static void -gtk_window_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +set_grip_cursor (GtkWindow *window) { - GtkWindow *window = GTK_WINDOW (widget); + GtkWidget *widget = GTK_WIDGET (window); GtkWindowPrivate *priv = window->priv; - GtkAllocation child_allocation; - GtkWidget *child; - guint border_width; - gtk_widget_set_allocation (widget, allocation); + if (priv->grip_window == NULL) + return; - child = gtk_bin_get_child (&(window->bin)); - if (child && gtk_widget_get_visible (child)) + if (gtk_widget_is_sensitive (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); + GdkWindowEdge edge; + GdkDisplay *display; + GdkCursorType cursor_type; + GdkCursor *cursor; - gtk_widget_size_allocate (child, &child_allocation); + cursor_type = GDK_LEFT_PTR; + + if (get_drag_edge (widget, &edge)) + { + switch (edge) + { + case GDK_WINDOW_EDGE_EAST: + cursor_type = GDK_RIGHT_SIDE; + break; + case GDK_WINDOW_EDGE_SOUTH_EAST: + cursor_type = GDK_BOTTOM_RIGHT_CORNER; + break; + case GDK_WINDOW_EDGE_SOUTH: + cursor_type = GDK_BOTTOM_SIDE; + break; + case GDK_WINDOW_EDGE_SOUTH_WEST: + cursor_type = GDK_BOTTOM_LEFT_CORNER; + break; + case GDK_WINDOW_EDGE_WEST: + cursor_type = GDK_LEFT_SIDE; + break; + default: ; + } + } + + display = gtk_widget_get_display (widget); + cursor = gdk_cursor_new_for_display (display, cursor_type); + gdk_window_set_cursor (priv->grip_window, cursor); + g_object_unref (cursor); } + else + gdk_window_set_cursor (priv->grip_window, NULL); +} + +static void +set_grip_shape (GtkWindow *window) +{ + GtkWindowPrivate *priv = window->priv; + cairo_region_t *region; + cairo_surface_t *surface; + cairo_t *cr; + double width, height; - if (gtk_widget_get_realized (widget) && priv->frame) + if (priv->grip_window == NULL) + return; + + 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); + + cr = cairo_create (surface); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); + cairo_paint (cr); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); + if (get_grip_junction (GTK_WIDGET (window)) & GTK_JUNCTION_CORNER_BOTTOMRIGHT) + { + cairo_move_to (cr, width, 0.0); + cairo_line_to (cr, width, height); + cairo_line_to (cr, 0.0, height); + } + else { - gdk_window_resize (priv->frame, - allocation->width + priv->frame_left + priv->frame_right, - allocation->height + priv->frame_top + priv->frame_bottom); + cairo_move_to (cr, 0.0, 0.0); + cairo_line_to (cr, width, height); + cairo_line_to (cr, 0.0, height); } + cairo_close_path (cr); + cairo_fill (cr); + cairo_destroy (cr); + region = gdk_cairo_region_create_from_surface (surface); + cairo_surface_destroy (surface); + + gdk_window_shape_combine_region (priv->grip_window, region, 0, 0); + cairo_region_destroy (region); } -static gint -gtk_window_event (GtkWidget *widget, GdkEvent *event) +static void +set_grip_position (GtkWindow *window) { - GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = window->priv; - gboolean return_val; + GdkRectangle rect; + + if (priv->grip_window == NULL) + return; + + gtk_window_get_resize_grip_area (window, &rect); + gdk_window_raise (priv->grip_window); + gdk_window_move_resize (priv->grip_window, + rect.x, rect.y, + rect.width, rect.height); +} + +static void +gtk_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWindow *window = GTK_WINDOW (widget); + GtkAllocation child_allocation; + GtkWidget *child; + guint border_width; - if (priv->frame && (event->any.window == priv->frame)) + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) { - if ((event->type != GDK_KEY_PRESS) && - (event->type != GDK_KEY_RELEASE) && - (event->type != GDK_FOCUS_CHANGE)) + /* 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)) { - g_signal_stop_emission_by_name (widget, "event"); - return_val = FALSE; - g_signal_emit (widget, window_signals[FRAME_EVENT], 0, event, &return_val); - return TRUE; + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, allocation->y, + allocation->width, allocation->height); } else { - g_object_unref (event->any.window); - event->any.window = g_object_ref (gtk_widget_get_window (widget)); + update_grip_visibility (window); + set_grip_position (window); } } - return FALSE; -} - -static gboolean -gtk_window_frame_event (GtkWindow *window, GdkEvent *event) -{ - GtkWindowPrivate *priv = window->priv; - GdkEventConfigure *configure_event; - GdkRectangle rect; - - switch (event->type) + child = gtk_bin_get_child (&(window->bin)); + if (child && gtk_widget_get_visible (child)) { - case GDK_CONFIGURE: - configure_event = (GdkEventConfigure *)event; - - /* Invalidate the decorations */ - rect.x = 0; - rect.y = 0; - rect.width = configure_event->width; - rect.height = configure_event->height; - - gdk_window_invalidate_rect (priv->frame, &rect, FALSE); + 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); - /* Pass on the (modified) configure event */ - configure_event->width -= priv->frame_left + priv->frame_right; - configure_event->height -= priv->frame_top + priv->frame_bottom; - return gtk_window_configure_event (GTK_WIDGET (window), configure_event); - break; - default: - break; + gtk_widget_size_allocate (child, &child_allocation); } - return FALSE; } static gint @@ -4964,6 +5239,15 @@ gtk_window_configure_event (GtkWidget *widget, GtkWindowPrivate *priv = window->priv; gboolean expected_reply = priv->configure_request_count > 0; + if (!gtk_widget_is_toplevel (GTK_WIDGET (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; + } + /* priv->configure_request_count incremented for each * configure request, and decremented to a min of 0 for * each configure notify. @@ -5014,11 +5298,301 @@ gtk_window_configure_event (GtkWidget *widget, 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)); return TRUE; } +static gboolean +gtk_window_state_event (GtkWidget *widget, + GdkEventWindowState *event) +{ + update_grip_visibility (GTK_WINDOW (widget)); + + return FALSE; +} + +static void +gtk_window_direction_changed (GtkWidget *widget, + GtkTextDirection prev_dir) +{ + GtkWindow *window = GTK_WINDOW (widget); + + set_grip_cursor (window); + set_grip_position (window); + set_grip_shape (window); +} + +static void +gtk_window_state_changed (GtkWidget *widget, + GtkStateType previous_state) +{ + GtkWindow *window = GTK_WINDOW (widget); + + update_grip_visibility (window); +} + +static void +gtk_window_style_updated (GtkWidget *widget) +{ + GtkWindow *window = GTK_WINDOW (widget); + GtkWindowPrivate *priv = window->priv; + GdkRectangle rect; + + GTK_WIDGET_CLASS (gtk_window_parent_class)->style_updated (widget); + + if (priv->grip_window != NULL && gtk_window_get_resize_grip_area (window, &rect)) + { + gdk_window_move_resize (priv->grip_window, + rect.x, rect.y, + rect.width, rect.height); + + set_grip_shape (window); + gtk_widget_queue_resize (widget); + } +} + +static void +resize_grip_create_window (GtkWindow *window) +{ + GtkWidget *widget; + GtkWindowPrivate *priv; + GdkWindowAttr attributes; + gint attributes_mask; + GdkRectangle rect; + + priv = window->priv; + widget = GTK_WIDGET (window); + + g_return_if_fail (gtk_widget_get_realized (widget)); + g_return_if_fail (priv->grip_window == NULL); + + gtk_window_get_resize_grip_area (window, &rect); + + attributes.x = rect.x; + attributes.y = rect.y; + attributes.width = rect.width; + attributes.height = rect.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + priv->grip_window = gdk_window_new (gtk_widget_get_window (widget), + &attributes, + attributes_mask); + + gdk_window_set_user_data (priv->grip_window, widget); + + gdk_window_raise (priv->grip_window); + + set_grip_shape (window); + update_grip_visibility (window); +} + +static void +resize_grip_destroy_window (GtkWindow *window) +{ + GtkWindowPrivate *priv = window->priv; + + gdk_window_set_user_data (priv->grip_window, NULL); + gdk_window_destroy (priv->grip_window); + priv->grip_window = NULL; + update_grip_visibility (window); +} + +/** + * gtk_window_set_has_resize_grip: + * @window: a #GtkWindow + * @value: %TRUE to allow a resize grip + * + * Sets whether @window has a corner resize grip. + * + * Note that the resize grip is only shown if the window + * is actually resizable and not maximized. Use + * gtk_window_resize_grip_is_visible() to find out if the + * resize grip is currently shown. + * + * Since: 3.0 + */ +void +gtk_window_set_has_resize_grip (GtkWindow *window, + gboolean value) +{ + GtkWidget *widget = GTK_WIDGET (window); + GtkWindowPrivate *priv = window->priv; + + value = value != FALSE; + + if (value != priv->has_resize_grip) + { + priv->has_resize_grip = value; + gtk_widget_queue_draw (widget); + + if (gtk_widget_get_realized (widget) && + gtk_widget_is_toplevel (GTK_WIDGET (widget))) + { + if (priv->has_resize_grip && priv->grip_window == NULL) + resize_grip_create_window (window); + else if (!priv->has_resize_grip && priv->grip_window != NULL) + resize_grip_destroy_window (window); + } + + g_object_notify (G_OBJECT (window), "has-resize-grip"); + } +} + +static void +update_grip_visibility (GtkWindow *window) +{ + GtkWindowPrivate *priv = window->priv; + gboolean val; + + val = gtk_window_resize_grip_is_visible (window); + + if (priv->grip_window != NULL) + { + if (val) + { + gdk_window_show (priv->grip_window); + set_grip_cursor (window); + } + else + { + gdk_window_hide (priv->grip_window); + } + } + + if (priv->resize_grip_visible != val) + { + priv->resize_grip_visible = val; + + g_object_notify (G_OBJECT (window), "resize-grip-visible"); + } +} + +/** + * gtk_window_resize_grip_is_visible: + * @window: a #GtkWindow + * + * Determines whether a resize grip is visible for the specified window. + * + * Returns: %TRUE if a resize grip exists and is visible + * + * Since: 3.0 + */ +gboolean +gtk_window_resize_grip_is_visible (GtkWindow *window) +{ + GtkWidget *widget; + GtkWindowPrivate *priv; + GdkWindowEdge edge; + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + priv = window->priv; + widget = GTK_WIDGET (window); + + if (priv->type == GTK_WINDOW_POPUP) + return FALSE; + + if (!priv->resizable) + return FALSE; + + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + return FALSE; + + if (gtk_widget_get_realized (widget)) + { + GdkWindowState state; + + state = gdk_window_get_state (gtk_widget_get_window (widget)); + + if (state & GDK_WINDOW_STATE_MAXIMIZED || state & GDK_WINDOW_STATE_FULLSCREEN) + return FALSE; + } + + if (!get_drag_edge (widget, &edge)) + return FALSE; + + return window->priv->has_resize_grip; +} + +/** + * gtk_window_get_has_resize_grip: + * @window: a #GtkWindow + * + * Determines whether the window may have a resize grip. + * + * Returns: %TRUE if the window has a resize grip + * + * Since: 3.0 + */ +gboolean +gtk_window_get_has_resize_grip (GtkWindow *window) +{ + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + return window->priv->has_resize_grip; +} + +/** + * gtk_window_get_resize_grip_area: + * @window: a #GtkWindow + * @rect: (out): a pointer to a #GdkRectangle which we should store + * the resize grip area + * + * If a window has a resize grip, this will retrieve the grip + * position, width and height into the specified #GdkRectangle. + * + * Returns: %TRUE if the resize grip's area was retrieved + * + * Since: 3.0 + */ +gboolean +gtk_window_get_resize_grip_area (GtkWindow *window, + GdkRectangle *rect) +{ + GtkWidget *widget = GTK_WIDGET (window); + GtkAllocation allocation; + gint grip_width; + gint grip_height; + + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + + if (!window->priv->has_resize_grip) + return FALSE; + + gtk_widget_get_allocation (widget, &allocation); + + gtk_widget_style_get (widget, + "resize-grip-width", &grip_width, + "resize-grip-height", &grip_height, + NULL); + + if (grip_width > allocation.width) + grip_width = allocation.width; + + if (grip_height > allocation.height) + grip_height = allocation.height; + + rect->width = grip_width; + rect->height = grip_height; + rect->y = allocation.y + allocation.height - grip_height; + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + rect->x = allocation.x + allocation.width - grip_width; + else + rect->x = allocation.x; + + return TRUE; +} + /* the accel_key and accel_mods fields of the key have to be setup * upon calling this function. it'll then return whether that key * is at all used as accelerator, and if so will OR in the @@ -5157,6 +5731,29 @@ gtk_window_key_release_event (GtkWidget *widget, return handled; } +static gint +gtk_window_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv; + GdkWindowEdge edge; + + 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); + + return TRUE; + } + + return FALSE; +} + static void gtk_window_real_activate_default (GtkWindow *window) { @@ -5169,16 +5766,6 @@ gtk_window_real_activate_focus (GtkWindow *window) gtk_window_activate_focus (window); } -static void -gtk_window_move_focus (GtkWindow *window, - GtkDirectionType dir) -{ - gtk_widget_child_focus (GTK_WIDGET (window), dir); - - if (!gtk_container_get_focus_child (GTK_CONTAINER (window))) - gtk_window_set_focus (window, NULL); -} - static gint gtk_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) @@ -5213,7 +5800,7 @@ do_focus_change (GtkWidget *widget, GdkDevice *dev = d->data; GdkEvent *fevent; - if (dev->source != GDK_SOURCE_KEYBOARD) + if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD) continue; /* Skip non-master keyboards that haven't @@ -5281,66 +5868,14 @@ gtk_window_focus_out_event (GtkWidget *widget, return FALSE; } -static GdkAtom atom_rcfiles = GDK_NONE; -static GdkAtom atom_iconthemes = GDK_NONE; - -static void -send_client_message_to_embedded_windows (GtkWidget *widget, - GdkAtom message_type) -{ - GList *embedded_windows; - - embedded_windows = g_object_get_qdata (G_OBJECT (widget), quark_gtk_embedded); - if (embedded_windows) - { - GdkEvent *send_event = gdk_event_new (GDK_CLIENT_EVENT); - int i; - - for (i = 0; i < 5; i++) - send_event->client.data.l[i] = 0; - send_event->client.data_format = 32; - send_event->client.message_type = message_type; - - while (embedded_windows) - { - GdkNativeWindow xid = GDK_GPOINTER_TO_NATIVE_WINDOW(embedded_windows->data); - 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); - } -} - -static gint -gtk_window_client_event (GtkWidget *widget, - GdkEventClient *event) -{ - if (!atom_rcfiles) - { - atom_rcfiles = gdk_atom_intern_static_string ("_GTK_READ_RCFILES"); - atom_iconthemes = gdk_atom_intern_static_string ("_GTK_LOAD_ICONTHEMES"); - } - - if (event->message_type == atom_rcfiles) - { - send_client_message_to_embedded_windows (widget, atom_rcfiles); - gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), FALSE); - } - - if (event->message_type == atom_iconthemes) - { - send_client_message_to_embedded_windows (widget, atom_iconthemes); - _gtk_icon_theme_check_reload (gtk_widget_get_display (widget)); - } - - return FALSE; -} - static void gtk_window_check_resize (GtkContainer *container) { - if (gtk_widget_get_visible (GTK_WIDGET (container))) + /* If the window is not toplevel anymore than it's embedded somewhere, + * so handle it like a normal window */ + if (!gtk_widget_is_toplevel (GTK_WIDGET (container))) + GTK_CONTAINER_CLASS (gtk_window_parent_class)->check_resize (container); + else if (gtk_widget_get_visible (GTK_WIDGET (container))) gtk_window_move_resize (GTK_WINDOW (container)); } @@ -5356,6 +5891,9 @@ gtk_window_focus (GtkWidget *widget, GtkWidget *old_focus_child; GtkWidget *parent; + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + return GTK_WIDGET_CLASS (gtk_window_parent_class)->focus (widget, direction); + container = GTK_CONTAINER (widget); window = GTK_WINDOW (widget); priv = window->priv; @@ -5405,6 +5943,22 @@ gtk_window_focus (GtkWidget *widget, return FALSE; } +static void +gtk_window_move_focus (GtkWidget *widget, + GtkDirectionType dir) +{ + if (!gtk_widget_is_toplevel (GTK_WIDGET (widget))) + { + GTK_WIDGET_CLASS (gtk_window_parent_class)->move_focus (widget, dir); + return; + } + + gtk_widget_child_focus (widget, dir); + + if (! gtk_container_get_focus_child (GTK_CONTAINER (widget))) + gtk_window_set_focus (GTK_WINDOW (widget), NULL); +} + static void gtk_window_real_set_focus (GtkWindow *window, GtkWidget *focus) @@ -5503,18 +6057,10 @@ gtk_window_real_set_focus (GtkWindow *window, } -static void -gtk_window_size_request_init (GtkSizeRequestIface *iface) -{ - iface->get_width = gtk_window_get_width; - iface->get_height = gtk_window_get_height; -} - - static void -gtk_window_get_width (GtkSizeRequest *widget, - gint *minimum_size, - gint *natural_size) +gtk_window_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) { GtkWindow *window; GtkWidget *child; @@ -5530,7 +6076,7 @@ gtk_window_get_width (GtkSizeRequest *widget, if (child && gtk_widget_get_visible (child)) { gint child_min, child_nat; - gtk_size_request_get_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat); + gtk_widget_get_preferred_width (child, &child_min, &child_nat); *minimum_size += child_min; *natural_size += child_nat; @@ -5538,9 +6084,9 @@ gtk_window_get_width (GtkSizeRequest *widget, } static void -gtk_window_get_height (GtkSizeRequest *widget, - gint *minimum_size, - gint *natural_size) +gtk_window_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) { GtkWindow *window; GtkWidget *child; @@ -5556,7 +6102,7 @@ gtk_window_get_height (GtkSizeRequest *widget, if (child && gtk_widget_get_visible (child)) { gint child_min, child_nat; - gtk_size_request_get_height (GTK_SIZE_REQUEST (child), &child_min, &child_nat); + gtk_widget_get_preferred_height (child, &child_min, &child_nat); *minimum_size += child_min; *natural_size += child_nat; @@ -5601,22 +6147,59 @@ _gtk_window_unset_focus_and_default (GtkWindow *window, while (child && child != widget) child = gtk_widget_get_parent (child); - if (child == widget) - gtk_window_set_default (window, NULL); - - g_object_unref (widget); - g_object_unref (window); + if (child == widget) + gtk_window_set_default (window, NULL); + + g_object_unref (widget); + g_object_unref (window); +} + +/********************************* + * Functions related to resizing * + *********************************/ + +static void +geometry_size_to_pixels (GdkGeometry *geometry, + guint flags, + guint *width, + guint *height) +{ + gint base_width = 0; + gint base_height = 0; + gint min_width = 0; + gint min_height = 0; + gint width_inc = 1; + gint height_inc = 1; + + if (flags & GDK_HINT_BASE_SIZE) + { + base_width = geometry->base_width; + base_height = geometry->base_height; + } + if (flags & GDK_HINT_MIN_SIZE) + { + min_width = geometry->min_width; + min_height = geometry->min_height; + } + if (flags & GDK_HINT_RESIZE_INC) + { + width_inc = geometry->width_inc; + height_inc = geometry->height_inc; + } + + if (width) + *width = MAX (*width * width_inc + base_width, min_width); + if (height) + *height = MAX (*height * height_inc + base_height, min_height); } -/********************************* - * Functions related to resizing * - *********************************/ - /* This function doesn't constrain to geometry hints */ static void -gtk_window_compute_configure_request_size (GtkWindow *window, - guint *width, - guint *height) +gtk_window_compute_configure_request_size (GtkWindow *window, + GdkGeometry *geometry, + guint flags, + guint *width, + guint *height) { GtkWindowPrivate *priv = window->priv; GtkRequisition requisition; @@ -5633,8 +6216,7 @@ gtk_window_compute_configure_request_size (GtkWindow *window, if (priv->need_default_size) { - gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), - &requisition, NULL); + gtk_widget_get_preferred_size (widget, &requisition, NULL); /* Default to requisition */ *width = requisition.width; @@ -5650,44 +6232,16 @@ gtk_window_compute_configure_request_size (GtkWindow *window, /* Override requisition with default size */ if (info) - { - gint base_width = 0; - gint base_height = 0; - gint min_width = 0; - gint min_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; - } - if (flags & GDK_HINT_MIN_SIZE) - { - min_width = geometry.min_width; - min_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 = MAX (info->default_width * width_inc + base_width, min_width); - + *width = info->default_width; if (info->default_height > 0) - *height = MAX (info->default_height * height_inc + base_height, min_height); + *height = info->default_height; + + if (info->default_is_geometry) + geometry_size_to_pixels (geometry, flags, + info->default_width > 0 ? width : NULL, + info->default_height > 0 ? height : NULL); } } else @@ -5705,10 +6259,14 @@ gtk_window_compute_configure_request_size (GtkWindow *window, if (info) { if (info->resize_width > 0) - *width = info->resize_width; - + *width = info->resize_width; if (info->resize_height > 0) - *height = info->resize_height; + *height = info->resize_height; + + if (info->resize_is_geometry) + geometry_size_to_pixels (geometry, flags, + info->resize_width > 0 ? width : NULL, + info->resize_height > 0 ? height : NULL); } /* Don't ever request zero width or height, its not supported by @@ -5759,9 +6317,9 @@ get_monitor_containing_pointer (GtkWindow *window) device_manager = gdk_display_get_device_manager (display); pointer = gdk_device_manager_get_client_pointer (device_manager); - gdk_display_get_device_state (display, pointer, - &pointer_screen, - &px, &py, NULL); + gdk_device_get_position (pointer, + &pointer_screen, + &px, &py); if (pointer_screen == window_screen) monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py); @@ -5849,32 +6407,29 @@ gtk_window_compute_configure_request (GtkWindow *window, GdkGeometry new_geometry; guint new_flags; int w, h; - GtkWidget *widget; GtkWindowPosition pos; GtkWidget *parent_widget; GtkWindowGeometryInfo *info; GdkScreen *screen; int x, y; - - widget = GTK_WIDGET (window); screen = gtk_window_check_screen (window); - gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), - NULL, NULL); - gtk_window_compute_configure_request_size (window, (guint *)&w, (guint *)&h); - gtk_window_compute_hints (window, &new_geometry, &new_flags); + gtk_window_compute_configure_request_size (window, + &new_geometry, new_flags, + (guint *)&w, (guint *)&h); + gtk_window_constrain_size (window, &new_geometry, new_flags, w, h, &w, &h); parent_widget = (GtkWidget*) priv->transient_parent; - + pos = get_effective_position (window); info = gtk_window_get_geometry_info (window, FALSE); - + /* by default, don't change position requested */ if (info) { @@ -5896,7 +6451,6 @@ gtk_window_compute_configure_request (GtkWindow *window, * * Not sure how to go about that. */ - switch (pos) { /* here we are only handling CENTER_ALWAYS @@ -5907,7 +6461,7 @@ gtk_window_compute_configure_request (GtkWindow *window, case GTK_WIN_POS_CENTER: center_window_on_monitor (window, w, h, &x, &y); break; - + case GTK_WIN_POS_CENTER_ON_PARENT: { GtkAllocation allocation; @@ -5915,7 +6469,7 @@ gtk_window_compute_configure_request (GtkWindow *window, gint monitor_num; GdkRectangle monitor; gint ox, oy; - + g_assert (gtk_widget_get_mapped (parent_widget)); /* established earlier */ gdk_window = gtk_widget_get_window (parent_widget); @@ -5949,8 +6503,8 @@ gtk_window_compute_configure_request (GtkWindow *window, { gint screen_width = gdk_screen_get_width (screen); gint screen_height = gdk_screen_get_height (screen); - gint monitor_num; - GdkRectangle monitor; + gint monitor_num; + GdkRectangle monitor; GdkDisplay *display; GdkDeviceManager *device_manager; GdkDevice *pointer; @@ -5961,15 +6515,15 @@ gtk_window_compute_configure_request (GtkWindow *window, device_manager = gdk_display_get_device_manager (display); pointer = gdk_device_manager_get_client_pointer (device_manager); - gdk_display_get_device_state (display, pointer, - &pointer_screen, - &px, &py, NULL); + gdk_device_get_position (pointer, + &pointer_screen, + &px, &py); if (pointer_screen == screen) monitor_num = gdk_screen_get_monitor_at_point (screen, px, py); else monitor_num = -1; - + x = px - w / 2; y = py - h / 2; x = CLAMP (x, 0, screen_width - w); @@ -5999,7 +6553,7 @@ gtk_window_compute_configure_request (GtkWindow *window, y = info->initial_y; gtk_window_constrain_position (window, w, h, &x, &y); } - + request->x = x; request->y = y; request->width = w; @@ -6084,6 +6638,7 @@ gtk_window_move_resize (GtkWindow *window) GtkWindowLastGeometryInfo saved_last_info; widget = GTK_WIDGET (window); + gdk_window = gtk_widget_get_window (widget); container = GTK_CONTAINER (widget); info = gtk_window_get_geometry_info (window, TRUE); @@ -6282,6 +6837,9 @@ gtk_window_move_resize (GtkWindow *window) /* gtk_window_configure_event() filled in widget->allocation */ gtk_widget_size_allocate (widget, &allocation); + set_grip_position (window); + update_grip_visibility (window); + gdk_window_process_updates (gdk_window, TRUE); gdk_window_configure_finished (gdk_window); @@ -6348,32 +6906,17 @@ gtk_window_move_resize (GtkWindow *window) /* Now send the configure request */ if (configure_request_pos_changed) - { - if (priv->frame) - { - gdk_window_move_resize (priv->frame, - new_request.x - priv->frame_left, - new_request.y - priv->frame_top, - new_request.width + priv->frame_left + priv->frame_right, - new_request.height + priv->frame_top + priv->frame_bottom); - gdk_window_resize (gdk_window, - new_request.width, new_request.height); - } - else - gdk_window_move_resize (gdk_window, - new_request.x, new_request.y, - new_request.width, new_request.height); - } + { + gdk_window_move_resize (gdk_window, + new_request.x, new_request.y, + new_request.width, new_request.height); + } else /* only size changed */ - { - if (priv->frame) - gdk_window_resize (priv->frame, - new_request.width + priv->frame_left + priv->frame_right, - new_request.height + priv->frame_top + priv->frame_bottom); - gdk_window_resize (gdk_window, - new_request.width, new_request.height); - } - + { + gdk_window_resize (gdk_window, + new_request.width, new_request.height); + } + if (priv->type == GTK_WINDOW_POPUP) { GtkAllocation allocation; @@ -6424,17 +6967,10 @@ gtk_window_move_resize (GtkWindow *window) /* Handle any position changes. */ if (configure_request_pos_changed) - { - if (priv->frame) - { - gdk_window_move (priv->frame, - new_request.x - priv->frame_left, - new_request.y - priv->frame_top); - } - else - gdk_window_move (gdk_window, - new_request.x, new_request.y); - } + { + gdk_window_move (gdk_window, + new_request.x, new_request.y); + } /* And run the resize queue. */ @@ -6540,7 +7076,7 @@ gtk_window_constrain_size (GtkWindow *window, /* Compute the set of geometry hints and flags for a window * based on the application set geometry, and requisition - * of the window. gtk_size_request_get_size() must have been + * of the window. gtk_widget_get_preferred_size() must have been * called first. */ static void @@ -6557,7 +7093,7 @@ gtk_window_compute_hints (GtkWindow *window, widget = GTK_WIDGET (window); - gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), &requisition, NULL); + gtk_widget_get_preferred_size (widget, &requisition, NULL); geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE); if (geometry_info) @@ -6572,28 +7108,52 @@ gtk_window_compute_hints (GtkWindow *window, if (geometry_info && geometry_info->widget) { - GtkRequisition requisition; - GtkRequisition child_requisition; - - /* FIXME: This really isn't right. It gets the min size wrong and forces - * callers to do horrible hacks like set a huge usize on the child requisition - * to get the base size right. We really want to find the answers to: - * - * - If the geometry widget was infinitely big, how much extra space - * would be needed for the stuff around it. + /* If the geometry widget is set, then the hints really apply to that + * widget. This is pretty much meaningless unless the window layout + * is such that the rest of the window adds fixed size borders to + * the geometry widget. Our job is to figure the size of the borders; + * We do that by asking how big the toplevel would be if the + * geometry widget was *really big*. * - * - If the geometry widget was infinitely small, how big would the - * window still have to be. + * +----------+ + * |AAAAAAAAA | At small sizes, the minimum sizes of widgets + * |GGGGG B| in the border can confuse things + * |GGGGG B| + * | B| + * +----------+ * - * Finding these answers would be a bit of a mess here. (Bug #68668) + * +-----------+ + * |AAAAAAAAA | When the geometry widget is large, things are + * |GGGGGGGGGGB| clearer. + * |GGGGGGGGGGB| + * |GGGGGGGGGG | + * +-----------+ */ - gtk_size_request_get_size (GTK_SIZE_REQUEST (geometry_info->widget), - &child_requisition, NULL); +#define TEMPORARY_SIZE 10000 /* 10,000 pixels should be bigger than real widget sizes */ + GtkRequisition requisition; + int current_width, current_height; + + _gtk_widget_override_size_request (geometry_info->widget, + TEMPORARY_SIZE, TEMPORARY_SIZE, + ¤t_width, ¤t_height); + gtk_widget_get_preferred_size (widget, + &requisition, NULL); + _gtk_widget_restore_size_request (geometry_info->widget, + current_width, current_height); - gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), - &requisition, NULL); - extra_width = requisition.width - child_requisition.width; - extra_height = requisition.height - child_requisition.height; + extra_width = requisition.width - TEMPORARY_SIZE; + extra_height = requisition.height - TEMPORARY_SIZE; + + if (extra_width < 0 || extra_width < 0) + { + g_warning("Toplevel size doesn't seem to directly depend on the " + "size of the geometry widget from gtk_window_set_geometry_hints(). " + "The geometry widget might not be in the window, or it might not " + "be packed into the window appropriately"); + extra_width = MAX(extra_width, 0); + extra_height = MAX(extra_height, 0); + } +#undef TEMPORARY_SIZE } /* We don't want to set GDK_HINT_POS in here, we just set it @@ -6606,27 +7166,39 @@ gtk_window_compute_hints (GtkWindow *window, new_geometry->base_width += extra_width; new_geometry->base_height += extra_height; } - else if (!(*new_flags & GDK_HINT_MIN_SIZE) && - (*new_flags & GDK_HINT_RESIZE_INC) && - ((extra_width != 0) || (extra_height != 0))) + else { + /* For simplicity, we always set the base hint, even when we + * don't expect it to have any visible effect. + * (Note: geometry_size_to_pixels() depends on this.) + */ *new_flags |= GDK_HINT_BASE_SIZE; - + new_geometry->base_width = extra_width; new_geometry->base_height = extra_height; + + /* As for X, if BASE_SIZE is not set but MIN_SIZE is set, then the + * base size is the minimum size */ + if (*new_flags & GDK_HINT_MIN_SIZE) + { + if (new_geometry->min_width > 0) + new_geometry->base_width += new_geometry->min_width; + if (new_geometry->min_height > 0) + new_geometry->base_height += new_geometry->min_height; + } } - + if (*new_flags & GDK_HINT_MIN_SIZE) { if (new_geometry->min_width < 0) new_geometry->min_width = requisition.width; else - new_geometry->min_width += extra_width; + new_geometry->min_width = MAX (requisition.width, new_geometry->min_width + extra_width); if (new_geometry->min_height < 0) new_geometry->min_height = requisition.height; else - new_geometry->min_height += extra_height; + new_geometry->min_height = MAX (requisition.height, new_geometry->min_height + extra_height); } else { @@ -6668,128 +7240,55 @@ static gboolean gtk_window_draw (GtkWidget *widget, cairo_t *cr) { - if (!gtk_widget_get_app_paintable (widget)) - gtk_paint_flat_box (gtk_widget_get_style (widget), - cr, - GTK_STATE_NORMAL, - GTK_SHADOW_NONE, widget, "base", - 0, 0, - gtk_widget_get_allocated_width (widget), - gtk_widget_get_allocated_height (widget)); - - if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw) - return GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr); - - return FALSE; -} + GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv; + GtkStyleContext *context; + gboolean ret = FALSE; -/** - * gtk_window_set_has_frame: - * @window: a #GtkWindow - * @setting: a boolean - * - * (Note: this is a special-purpose function for the framebuffer port, - * that causes GTK+ to draw its own window border. For most applications, - * you want gtk_window_set_decorated() instead, which tells the window - * manager whether to draw the window border.) - * - * If this function is called on a window with setting of %TRUE, before - * it is realized or showed, it will have a "frame" window around - * @window->window, accessible in @window->frame. Using the signal - * frame_event you can receive all events targeted at the frame. - * - * This function is used by the linux-fb port to implement managed - * windows, but it could conceivably be used by X-programs that - * want to do their own window decorations. - * - **/ -void -gtk_window_set_has_frame (GtkWindow *window, - gboolean setting) -{ - GtkWindowPrivate *priv; + context = gtk_widget_get_style_context (widget); - g_return_if_fail (GTK_IS_WINDOW (window)); - g_return_if_fail (!gtk_widget_get_realized (GTK_WIDGET (window))); + gtk_style_context_save (context); - priv = window->priv; + if (!gtk_widget_get_app_paintable (widget)) + { + GtkStateFlags state; - priv->has_frame = setting != FALSE; -} + state = gtk_widget_get_state_flags (widget); -/** - * gtk_window_get_has_frame: - * @window: a #GtkWindow - * - * Accessor for whether the window has a frame window exterior to - * @window->window. Gets the value set by gtk_window_set_has_frame (). - * - * Return value: %TRUE if a frame has been added to the window - * via gtk_window_set_has_frame(). - **/ -gboolean -gtk_window_get_has_frame (GtkWindow *window) -{ - g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + if (gtk_window_has_toplevel_focus (GTK_WINDOW (widget))) + state |= GTK_STATE_FLAG_FOCUSED; - return window->priv->has_frame; -} + 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_window_set_frame_dimensions: - * @window: a #GtkWindow that has a frame - * @left: The width of the left border - * @top: The height of the top border - * @right: The width of the right border - * @bottom: The height of the bottom border - * - * (Note: this is a special-purpose function intended for the framebuffer - * port; see gtk_window_set_has_frame(). It will have no effect on the - * window border drawn by the window manager, which is the normal - * case when using the X Window system.) - * - * For windows with frames (see gtk_window_set_has_frame()) this function - * can be used to change the size of the frame border. - **/ -void -gtk_window_set_frame_dimensions (GtkWindow *window, - gint left, - gint top, - gint right, - gint bottom) -{ - GtkWindowPrivate *priv; - GtkAllocation allocation; - GtkWidget *widget; + gtk_style_context_restore (context); - g_return_if_fail (GTK_IS_WINDOW (window)); + if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw) + ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr); - priv = window->priv; - widget = GTK_WIDGET (window); + if (priv->grip_window != NULL && + gtk_cairo_should_draw_window (cr, priv->grip_window)) + { + GdkRectangle rect; - if (priv->frame_left == left && - priv->frame_top == top && - priv->frame_right == right && - priv->frame_bottom == bottom) - return; + gtk_style_context_save (context); + cairo_save (cr); - priv->frame_left = left; - priv->frame_top = top; - priv->frame_right = right; - priv->frame_bottom = bottom; + gtk_cairo_transform_to_window (cr, widget, priv->grip_window); + gtk_window_get_resize_grip_area (GTK_WINDOW (widget), &rect); - if (gtk_widget_get_realized (widget) && priv->frame) - { - gtk_widget_get_allocation (widget, &allocation); + 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); - gint width = allocation.width + left + right; - gint height = allocation.height + top + bottom; - gdk_window_resize (priv->frame, width, height); - gtk_decorated_window_move_resize_window (window, - left, top, - allocation.width, - allocation.height); + cairo_restore (cr); + gtk_style_context_restore (context); } + + return ret; } /** @@ -6906,10 +7405,7 @@ gtk_window_iconify (GtkWindow *window) priv->iconify_initially = TRUE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_iconify (toplevel); @@ -6942,10 +7438,7 @@ gtk_window_deiconify (GtkWindow *window) priv->iconify_initially = FALSE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_deiconify (toplevel); @@ -6983,10 +7476,7 @@ gtk_window_stick (GtkWindow *window) priv->stick_initially = TRUE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_stick (toplevel); @@ -7021,10 +7511,7 @@ gtk_window_unstick (GtkWindow *window) priv->stick_initially = FALSE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_unstick (toplevel); @@ -7064,10 +7551,7 @@ gtk_window_maximize (GtkWindow *window) priv->maximize_initially = TRUE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_maximize (toplevel); @@ -7102,10 +7586,7 @@ gtk_window_unmaximize (GtkWindow *window) priv->maximize_initially = FALSE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_unmaximize (toplevel); @@ -7142,10 +7623,7 @@ gtk_window_fullscreen (GtkWindow *window) priv->fullscreen_initially = TRUE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_fullscreen (toplevel); @@ -7182,10 +7660,7 @@ gtk_window_unfullscreen (GtkWindow *window) priv->fullscreen_initially = FALSE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_unfullscreen (toplevel); @@ -7236,10 +7711,7 @@ gtk_window_set_keep_above (GtkWindow *window, if (setting) priv->below_initially = FALSE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_set_keep_above (toplevel, setting); @@ -7290,10 +7762,7 @@ gtk_window_set_keep_below (GtkWindow *window, if (setting) priv->above_initially = FALSE; - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); if (toplevel != NULL) gdk_window_set_keep_below (toplevel, setting); @@ -7317,11 +7786,18 @@ gtk_window_set_resizable (GtkWindow *window, priv = window->priv; - priv->resizable = (resizable != FALSE); + resizable = (resizable != FALSE); - g_object_notify (G_OBJECT (window), "resizable"); + if (priv->resizable != resizable) + { + priv->resizable = (resizable != FALSE); - gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); + update_grip_visibility (window); + + gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window)); + + g_object_notify (G_OBJECT (window), "resizable"); + } } /** @@ -7416,20 +7892,14 @@ gtk_window_begin_resize_drag (GtkWindow *window, gint root_y, guint32 timestamp) { - GtkWindowPrivate *priv; GtkWidget *widget; GdkWindow *toplevel; - + g_return_if_fail (GTK_IS_WINDOW (window)); widget = GTK_WIDGET (window); g_return_if_fail (gtk_widget_get_visible (widget)); - priv = window->priv; - - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); gdk_window_begin_resize_drag (toplevel, edge, button, @@ -7437,48 +7907,6 @@ gtk_window_begin_resize_drag (GtkWindow *window, timestamp); } -/** - * gtk_window_get_frame_dimensions: - * @window: a #GtkWindow - * @left: (out) (allow-none): location to store the width of the frame at the left, or %NULL - * @top: (out) (allow-none): location to store the height of the frame at the top, or %NULL - * @right: (out) (allow-none): location to store the width of the frame at the returns, or %NULL - * @bottom: (out) (allow-none): location to store the height of the frame at the bottom, or %NULL - * - * (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.) - * - * Retrieves the dimensions of the frame window for this toplevel. - * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions(). - **/ -void -gtk_window_get_frame_dimensions (GtkWindow *window, - gint *left, - gint *top, - gint *right, - gint *bottom) -{ - GtkWindowPrivate *priv; - - g_return_if_fail (GTK_IS_WINDOW (window)); - - priv = window->priv; - - if (left) - *left = priv->frame_left; - if (top) - *top = priv->frame_top; - if (right) - *right = priv->frame_right; - if (bottom) - *bottom = priv->frame_bottom; -} - /** * gtk_window_begin_move_drag: * @window: a #GtkWindow @@ -7502,20 +7930,14 @@ gtk_window_begin_move_drag (GtkWindow *window, gint root_y, guint32 timestamp) { - GtkWindowPrivate *priv; GtkWidget *widget; GdkWindow *toplevel; - + g_return_if_fail (GTK_IS_WINDOW (window)); widget = GTK_WIDGET (window); g_return_if_fail (gtk_widget_get_visible (widget)); - priv = window->priv; - - if (priv->frame) - toplevel = priv->frame; - else - toplevel = gtk_widget_get_window (widget); + toplevel = gtk_widget_get_window (widget); gdk_window_begin_move_drag (toplevel, button, @@ -7523,111 +7945,64 @@ gtk_window_begin_move_drag (GtkWindow *window, timestamp); } -GdkVisual * -_gtk_window_get_visual (GtkWindow *window) -{ - g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); - - return window->priv->visual; -} - /** - * gtk_window_set_visual: - * @window: window to set the visual from - * @visual: the new visual to use + * gtk_window_set_screen: + * @window: a #GtkWindow. + * @screen: a #GdkScreen. * - * Sets the #GdkVisual used to display @window; if the window - * is already mapped, it will be unmapped, and then remapped - * with the new visual. It is fine if @visual is on a - * different #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. * - * By default, a window's visual is set to the system visual - * of the default screen. - **/ + * Since: 2.2 + */ void -gtk_window_set_visual (GtkWindow *window, - GdkVisual *visual) +gtk_window_set_screen (GtkWindow *window, + GdkScreen *screen) { GtkWindowPrivate *priv; GtkWidget *widget; - GdkVisual *previous_visual; - GdkScreen *previous_screen, *screen; + GdkScreen *previous_screen; gboolean was_mapped; - + g_return_if_fail (GTK_IS_WINDOW (window)); - g_return_if_fail (GDK_IS_VISUAL (visual)); + g_return_if_fail (GDK_IS_SCREEN (screen)); priv = window->priv; - if (priv->visual == visual) + if (screen == priv->screen) return; widget = GTK_WIDGET (window); - previous_visual = priv->visual; - previous_screen = gdk_visual_get_screen (previous_visual); - screen = gdk_visual_get_screen (visual); + previous_screen = priv->screen; was_mapped = gtk_widget_get_mapped (widget); if (was_mapped) gtk_widget_unmap (widget); if (gtk_widget_get_realized (widget)) gtk_widget_unrealize (widget); - g_object_freeze_notify (G_OBJECT (window)); gtk_window_free_key_hash (window); - priv->visual = visual; + priv->screen = screen; gtk_widget_reset_rc_styles (widget); - if (previous_screen != screen) + if (screen != previous_screen) { - g_signal_handlers_disconnect_by_func (previous_screen, - gtk_window_on_composited_changed, window); - g_signal_connect (screen, "composited-changed", - G_CALLBACK (gtk_window_on_composited_changed), window); - + if (previous_screen) + g_signal_handlers_disconnect_by_func (previous_screen, + gtk_window_on_composited_changed, window); + g_signal_connect (screen, "composited-changed", + G_CALLBACK (gtk_window_on_composited_changed), window); + _gtk_widget_propagate_screen_changed (widget, previous_screen); _gtk_widget_propagate_composited_changed (widget); - g_object_notify (G_OBJECT (window), "screen"); } - g_object_notify (G_OBJECT (window), "visual"); + g_object_notify (G_OBJECT (window), "screen"); - g_object_thaw_notify (G_OBJECT (window)); if (was_mapped) gtk_widget_map (widget); } -/** - * gtk_window_set_screen: - * @window: a #GtkWindow. - * @screen: a #GdkScreen. - * - * Sets the #GdkScreen where the @window is displayed. If - * the @screen is equal to @window's current screen, this - * function does nothing. If it is not and the window is - * already mapped, it will be unmapped, and then remapped - * on the new screen. - * - * This function resets @window's visual to the system - * visual of the given @screen. If you want to use a - * different visual, consider using gtk_window_set_visual() - * instead. - * - * Since: 2.2 - */ -void -gtk_window_set_screen (GtkWindow *window, - GdkScreen *screen) -{ - g_return_if_fail (GTK_IS_WINDOW (window)); - g_return_if_fail (GDK_IS_SCREEN (screen)); - - if (screen == gdk_visual_get_screen (window->priv->visual)) - return; - - gtk_window_set_visual (window, - gdk_screen_get_system_visual (screen)); -} - static void gtk_window_on_composited_changed (GdkScreen *screen, GtkWindow *window) @@ -7642,8 +8017,8 @@ gtk_window_check_screen (GtkWindow *window) { GtkWindowPrivate *priv = window->priv; - if (priv->visual) - return gdk_visual_get_screen (priv->visual); + if (priv->screen) + return priv->screen; else { g_warning ("Screen for GtkWindow not set; you must always set\n" @@ -7667,7 +8042,7 @@ gtk_window_get_screen (GtkWindow *window) { g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); - return gdk_visual_get_screen (window->priv->visual); + return window->priv->screen; } /** @@ -7714,37 +8089,20 @@ gtk_window_has_toplevel_focus (GtkWindow *window) return window->priv->has_toplevel_focus; } +G_DEFINE_TYPE (GtkWindowGroup, gtk_window_group, G_TYPE_OBJECT) + static void -gtk_window_group_class_init (GtkWindowGroupClass *klass) +gtk_window_group_init (GtkWindowGroup *group) { - g_type_class_add_private (klass, sizeof (GtkWindowGroupPrivate)); + group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group, + GTK_TYPE_WINDOW_GROUP, + GtkWindowGroupPrivate); } -GType -gtk_window_group_get_type (void) +static void +gtk_window_group_class_init (GtkWindowGroupClass *klass) { - static GType window_group_type = 0; - - if (!window_group_type) - { - const GTypeInfo window_group_info = - { - sizeof (GtkWindowGroupClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_window_group_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkWindowGroup), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL, - }; - - window_group_type = g_type_register_static (G_TYPE_OBJECT, I_("GtkWindowGroup"), - &window_group_info, 0); - } - - return window_group_type; + g_type_class_add_private (klass, sizeof (GtkWindowGroupPrivate)); } /** @@ -7763,14 +8121,16 @@ gtk_window_group_new (void) static void window_group_cleanup_grabs (GtkWindowGroup *group, - GtkWindow *window) + GtkWindow *window) { GtkWindowGroupPrivate *priv; GtkDeviceGrabInfo *info; GSList *tmp_list; GSList *to_remove = NULL; - tmp_list = group->grabs; + priv = group->priv; + + tmp_list = priv->grabs; while (tmp_list) { if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window) @@ -7785,7 +8145,6 @@ window_group_cleanup_grabs (GtkWindowGroup *group, to_remove = g_slist_delete_link (to_remove, to_remove); } - priv = GTK_WINDOW_GROUP_GET_PRIVATE (group); tmp_list = priv->device_grabs; while (tmp_list) @@ -7874,8 +8233,8 @@ gtk_window_group_remove_window (GtkWindowGroup *window_group, * * Returns a list of the #GtkWindows that belong to @window_group. * - * Returns: (element-type GtkWidget) (transfer container): A newly-allocated list of - * windows inside the group. + * Returns: (element-type GtkWindow) (transfer container): A + * newly-allocated list of windows inside the group. * * Since: 2.14 **/ @@ -7897,6 +8256,8 @@ gtk_window_group_list_windows (GtkWindowGroup *window_group) group_windows = g_list_prepend (group_windows, window); } + g_list_free (toplevels); + return g_list_reverse (group_windows); } @@ -7953,7 +8314,7 @@ gtk_window_has_group (GtkWindow *window) * Gets the current grab widget of the given group, * see gtk_grab_add(). * - * Returns: the current grab widget of the group + * Returns: (transfer none): the current grab widget of the group * * Since: 2.22 */ @@ -7962,11 +8323,32 @@ gtk_window_group_get_current_grab (GtkWindowGroup *window_group) { g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL); - if (window_group->grabs) - return GTK_WIDGET (window_group->grabs->data); + if (window_group->priv->grabs) + return GTK_WIDGET (window_group->priv->grabs->data); return NULL; } +void +_gtk_window_group_add_grab (GtkWindowGroup *window_group, + GtkWidget *widget) +{ + GtkWindowGroupPrivate *priv; + + priv = window_group->priv; + priv->grabs = g_slist_prepend (priv->grabs, widget); +} + +void +_gtk_window_group_remove_grab (GtkWindowGroup *window_group, + GtkWidget *widget) +{ + GtkWindowGroupPrivate *priv; + + priv = window_group->priv; + priv->grabs = g_slist_remove (priv->grabs, widget); +} + + void _gtk_window_group_add_device_grab (GtkWindowGroup *window_group, GtkWidget *widget, @@ -7976,7 +8358,7 @@ _gtk_window_group_add_device_grab (GtkWindowGroup *window_group, GtkWindowGroupPrivate *priv; GtkDeviceGrabInfo *info; - priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group); + priv = window_group->priv; info = g_slice_new0 (GtkDeviceGrabInfo); info->widget = widget; @@ -7996,7 +8378,7 @@ _gtk_window_group_remove_device_grab (GtkWindowGroup *window_group, GSList *list, *node = NULL; GdkDevice *other_device; - priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group); + priv = window_group->priv; other_device = gdk_device_get_associated_device (device); list = priv->device_grabs; @@ -8031,7 +8413,7 @@ _gtk_window_group_remove_device_grab (GtkWindowGroup *window_group, * * Returns the current grab widget for @device, or %NULL if none. * - * Returns: The grab widget, or %NULL + * Returns: (transfer none): The grab widget, or %NULL * * Since: 3.0 */ @@ -8047,7 +8429,7 @@ gtk_window_group_get_current_device_grab (GtkWindowGroup *window_group, g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL); g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); - priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group); + priv = window_group->priv; list = priv->device_grabs; other_device = gdk_device_get_associated_device (device); @@ -8074,7 +8456,7 @@ _gtk_window_group_widget_is_blocked_for_device (GtkWindowGroup *window_group, GdkDevice *other_device; GSList *list; - priv = GTK_WINDOW_GROUP_GET_PRIVATE (window_group); + priv = window_group->priv; other_device = gdk_device_get_associated_device (device); list = priv->device_grabs; @@ -8324,7 +8706,7 @@ gtk_XParseGeometry (const char *string, * gtk_init (&argc, &argv); * * window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - * vbox = gtk_vbox_new (FALSE, 0); + * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); * * gtk_container_add (GTK_CONTAINER (window), vbox); * fill_with_content (vbox); @@ -8358,6 +8740,7 @@ gtk_window_parse_geometry (GtkWindow *window, { gint result, x = 0, y = 0; guint w, h; + GtkWidget *child; GdkGravity grav; gboolean size_set, pos_set; GdkScreen *screen; @@ -8365,6 +8748,12 @@ gtk_window_parse_geometry (GtkWindow *window, g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); g_return_val_if_fail (geometry != NULL, FALSE); + child = gtk_bin_get_child (GTK_BIN (window)); + if (!child || !gtk_widget_get_visible (child)) + g_warning ("gtk_window_parse_geometry() called on a window with no " + "visible children; the window should be set up before " + "gtk_window_parse_geometry() is called."); + screen = gtk_window_check_screen (window); result = gtk_XParseGeometry (geometry, &x, &y, &w, &h); @@ -8717,7 +9106,7 @@ _gtk_window_set_is_active (GtkWindow *window, * _gtk_window_set_is_toplevel: * @window: a #GtkWindow * @is_toplevel: %TRUE if the window is still a real toplevel (nominally a - * parent of the root window); %FALSE if it is not (for example, for an + * child of the root window); %FALSE if it is not (for example, for an * in-process, parented GtkPlug) * * Internal function used by #GtkPlug when it gets parented/unparented by a @@ -8726,9 +9115,10 @@ _gtk_window_set_is_active (GtkWindow *window, */ void _gtk_window_set_is_toplevel (GtkWindow *window, - gboolean is_toplevel) + gboolean is_toplevel) { GtkWidget *widget; + GtkWidget *toplevel; widget = GTK_WIDGET (window); @@ -8742,13 +9132,45 @@ _gtk_window_set_is_toplevel (GtkWindow *window, if (is_toplevel) { + /* Pass through regular pathways of an embedded toplevel + * to go through unmapping and hiding the widget before + * becomming a toplevel again. + * + * We remain hidden after becomming toplevel in order to + * avoid problems during an embedded toplevel's dispose cycle + * (When a toplevel window is shown it tries to grab focus again, + * this causes problems while disposing). + */ + gtk_widget_hide (widget); + + /* Save the toplevel this widget was previously anchored into before + * propagating a hierarchy-changed. + * + * Usually this happens by way of gtk_widget_unparent() and we are + * already unanchored at this point, just adding this clause incase + * things happen differently. + */ + toplevel = gtk_widget_get_toplevel (widget); + if (!gtk_widget_is_toplevel (toplevel)) + toplevel = NULL; + _gtk_widget_set_is_toplevel (widget, TRUE); + + /* When a window becomes toplevel after being embedded and anchored + * 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); + _gtk_widget_propagate_hierarchy_changed (widget, toplevel); + toplevel_list = g_slist_prepend (toplevel_list, window); } else { _gtk_widget_set_is_toplevel (widget, FALSE); toplevel_list = g_slist_remove (toplevel_list, window); + + _gtk_widget_propagate_hierarchy_changed (widget, widget); } } @@ -8880,3 +9302,27 @@ _gtk_window_get_wmclass (GtkWindow *window, *wmclass_name = priv->wmclass_name; *wmclass_class = priv->wmclass_class; } + +/** + * gtk_window_set_has_user_ref_count: + * @window: a #GtkWindow + * @setting: the new value + * + * Tells GTK+ whether to drop its extra reference to the window + * when gtk_window_destroy() is called. + * + * This function is only exported for the benefit of language + * bindings which may need to keep the window alive until their + * wrapper object is garbage collected. There is no justification + * for ever calling this function in an application. + * + * Since: 3.0 + */ +void +gtk_window_set_has_user_ref_count (GtkWindow *window, + gboolean setting) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->priv->has_user_ref_count = setting; +}