#include "gtkmarshalers.h"
#include "gtkplug.h"
#include "gtkbuildable.h"
-#include "gtksizerequest.h"
+#include "gtkwidgetprivate.h"
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
* @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().
+ *
* <refsect2 id="GtkWindow-BUILDER-UI">
* <title>GtkWindow as GtkBuildable</title>
* <para>
GtkWindowGroup *group;
GdkModifierType mnemonic_modifier;
- GdkVisual *visual;
+ GdkScreen *screen;
GdkWindow *frame;
GdkWindowTypeHint gdk_type_hint;
+ GtkApplication *application;
+
gdouble opacity;
+ GdkWindow *grip_window;
+
gchar *startup_id;
gchar *title;
gchar *wmclass_class;
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 {
PROP_ICON,
PROP_ICON_NAME,
PROP_SCREEN,
- PROP_VISUAL,
PROP_TYPE_HINT,
PROP_SKIP_TASKBAR_HINT,
PROP_SKIP_PAGER_HINT,
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,
*/
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;
};
};
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);
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,
GdkEventFocus *event);
static gint gtk_window_focus_out_event (GtkWidget *widget,
GdkEventFocus *event);
+static void gtk_window_style_set (GtkWidget *widget,
+ GtkStyle *style);
static gint gtk_window_client_event (GtkWidget *widget,
GdkEventClient *event);
+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);
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);
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,
/* 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;
}
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;
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;
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_set = gtk_window_style_set;
container_class->check_resize = gtk_window_check_resize;
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));
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",
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:
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));
+
+
+ /* Signals
+ */
+ /**
+ * GtkWindow:application:
+ *
+ * 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
+ */
+ 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),
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);
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;
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);
gtk_decorated_window_init (window);
- g_signal_connect (gdk_screen_get_default (), "composited-changed",
+ g_signal_connect (priv->screen, "composited-changed",
G_CALLBACK (gtk_window_on_composited_changed), window);
}
{
GtkWindow *window = GTK_WINDOW (object);
GtkWindowPrivate *priv = window->priv;
-
+
switch (prop_id)
{
case PROP_TYPE:
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));
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));
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;
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);
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;
GParamSpec *pspec,
GtkWindow *window)
{
- gtk_window_set_screen (window, gtk_window_get_screen (parent));
+ gtk_window_set_screen (window, parent->priv->screen);
}
static void
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);
return window->priv->opacity;
}
+/**
+ * gtk_window_get_application:
+ * @window: a #GtkWindow
+ *
+ * Gets the #GtkApplication associated with the window (if any).
+ *
+ * Return value: 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: 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
{
gtk_window_set_gravity (window, geometry->win_gravity);
}
-
+
gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
}
}
info->realized = TRUE;
+
+ gdk_window_set_icon_list (gtk_widget_get_window (widget), icon_list);
if (info->using_themed_icon)
{
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
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));
}
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
{
}
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;
toplevel_list = g_slist_remove (toplevel_list, window);
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
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)
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);
GtkContainer *container = GTK_CONTAINER (window);
gboolean need_resize;
- 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);
/* 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);
+ gtk_window_move_focus (widget, GTK_DIR_TAB_FORWARD);
if (priv->modal)
gtk_grab_add (widget);
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
+ _gtk_widget_set_visible_flag (widget, FALSE);
gtk_widget_unmap (widget);
if (priv->modal)
if (priv->frame)
gdk_window_show (priv->frame);
+ if (priv->grip_window)
+ gdk_window_show (priv->grip_window);
+
if (!disable_startup_notification)
{
/* Do we have a custom startup-notification id? */
{
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
- GtkWindowGeometryInfo *info;
+ GtkWindowGeometryInfo *info;
GdkWindow *gdk_window;
GdkWindowState state;
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 */
GDK_BUTTON_RELEASE_MASK);
attributes_mask = GDK_WA_VISUAL;
-
+
priv->frame = gdk_window_new (gtk_widget_get_root_window (widget),
&attributes, attributes_mask);
/* Icons */
gtk_window_realize_icon (window);
+
+ if (priv->has_resize_grip)
+ resize_grip_create_window (window);
}
static void
/* 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 GdkWindowEdge
+get_grip_edge (GtkWidget *widget)
+{
+ return gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR
+ ? GDK_WINDOW_EDGE_SOUTH_EAST
+ : GDK_WINDOW_EDGE_SOUTH_WEST;
+}
+
+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
+set_grip_cursor (GtkWindow *window)
+{
+ GtkWidget *widget = GTK_WIDGET (window);
+ GtkWindowPrivate *priv = window->priv;
+
+ if (priv->grip_window == NULL)
+ return;
+
+ if (gtk_widget_is_sensitive (widget))
+ {
+ GdkWindowEdge edge;
+ GdkDisplay *display;
+ GdkCursorType cursor_type;
+ GdkCursor *cursor;
+
+ 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);
+ gdk_cursor_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 (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_edge (GTK_WIDGET (window)) == GDK_WINDOW_EDGE_SOUTH_EAST)
+ {
+ cairo_move_to (cr, width, 0.0);
+ cairo_line_to (cr, width, height);
+ cairo_line_to (cr, 0.0, height);
+ }
+ else
+ {
+ 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 void
+set_grip_position (GtkWindow *window)
+{
+ GtkWindowPrivate *priv = window->priv;
+ 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)
gtk_widget_size_allocate (child, &child_allocation);
}
- if (gtk_widget_get_realized (widget) && priv->frame)
+ if (gtk_widget_get_realized (widget))
{
- gdk_window_resize (priv->frame,
- allocation->width + priv->frame_left + priv->frame_right,
- allocation->height + priv->frame_top + priv->frame_bottom);
+ if (priv->frame)
+ gdk_window_resize (priv->frame,
+ allocation->width + priv->frame_left + priv->frame_right,
+ allocation->height + priv->frame_top + priv->frame_bottom);
+ update_grip_visibility (window);
+ set_grip_position (window);
}
}
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;
}
-/* 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
- * accel_flags member of the key.
- */
-gboolean
-_gtk_window_query_nonaccels (GtkWindow *window,
- guint accel_key,
- GdkModifierType accel_mods)
+static gboolean
+gtk_window_state_event (GtkWidget *widget,
+ GdkEventWindowState *event)
{
- GtkWindowPrivate *priv;
+ update_grip_visibility (GTK_WINDOW (widget));
- g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+ return FALSE;
+}
- priv = window->priv;
+static void
+gtk_window_direction_changed (GtkWidget *widget,
+ GtkTextDirection prev_dir)
+{
+ GtkWindow *window = GTK_WINDOW (widget);
- /* movement keys are considered locked accels */
- if (!accel_mods)
- {
- static const guint bindings[] = {
- GDK_KEY_space, GDK_KEY_KP_Space, GDK_KEY_Return, GDK_KEY_ISO_Enter, GDK_KEY_KP_Enter, GDK_KEY_Up, GDK_KEY_KP_Up, GDK_KEY_Down, GDK_KEY_KP_Down,
- GDK_KEY_Left, GDK_KEY_KP_Left, GDK_KEY_Right, GDK_KEY_KP_Right, GDK_KEY_Tab, GDK_KEY_KP_Tab, GDK_KEY_ISO_Left_Tab,
- };
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (bindings); i++)
- if (bindings[i] == accel_key)
- return TRUE;
- }
+ set_grip_cursor (window);
+ set_grip_position (window);
+ set_grip_shape (window);
+}
- /* mnemonics are considered locked accels */
+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_set (GtkWidget *widget,
+ GtkStyle *style)
+{
+ GtkWindow *window = GTK_WINDOW (widget);
+ GtkWindowPrivate *priv = window->priv;
+ GdkRectangle rect;
+
+ 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))
+ {
+ 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_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: 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;
+ GtkStyle *style;
+ 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);
+ style = gtk_widget_get_style (widget);
+
+ 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
+ * accel_flags member of the key.
+ */
+gboolean
+_gtk_window_query_nonaccels (GtkWindow *window,
+ guint accel_key,
+ GdkModifierType accel_mods)
+{
+ GtkWindowPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+ priv = window->priv;
+
+ /* movement keys are considered locked accels */
+ if (!accel_mods)
+ {
+ static const guint bindings[] = {
+ GDK_KEY_space, GDK_KEY_KP_Space, GDK_KEY_Return, GDK_KEY_ISO_Enter, GDK_KEY_KP_Enter, GDK_KEY_Up, GDK_KEY_KP_Up, GDK_KEY_Down, GDK_KEY_KP_Down,
+ GDK_KEY_Left, GDK_KEY_KP_Left, GDK_KEY_Right, GDK_KEY_KP_Right, GDK_KEY_Tab, GDK_KEY_KP_Tab, GDK_KEY_ISO_Left_Tab,
+ };
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (bindings); i++)
+ if (bindings[i] == accel_key)
+ return TRUE;
+ }
+
+ /* mnemonics are considered locked accels */
if (accel_mods == priv->mnemonic_modifier)
{
GtkMnemonicHash *mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
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)
{
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)
return FALSE;
}
+static void
+gtk_window_move_focus (GtkWidget *widget,
+ GtkDirectionType dir)
+{
+ 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)
}
-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;
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;
}
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;
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;
* 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);
+}
+
/* 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;
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;
/* 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
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
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,
/* 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);
gdk_window_resize (gdk_window,
new_request.width, new_request.height);
}
-
+
if (priv->type == GTK_WINDOW_POPUP)
{
GtkAllocation allocation;
/* 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
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)
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);
+
+ extra_width = requisition.width - TEMPORARY_SIZE;
+ extra_height = requisition.height - TEMPORARY_SIZE;
- 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;
+ 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
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
{
gtk_window_draw (GtkWidget *widget,
cairo_t *cr)
{
+ GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+ gboolean ret = FALSE;
+
if (!gtk_widget_get_app_paintable (widget))
gtk_paint_flat_box (gtk_widget_get_style (widget),
cr,
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);
+ ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
- return FALSE;
+ if (priv->grip_window != NULL &&
+ gtk_cairo_should_draw_window (cr, priv->grip_window))
+ {
+ GdkRectangle rect;
+
+ cairo_save (cr);
+ gtk_cairo_transform_to_window (cr, widget, priv->grip_window);
+ gtk_window_get_resize_grip_area (GTK_WINDOW (widget), &rect);
+ gtk_paint_resize_grip (gtk_widget_get_style (widget),
+ cr,
+ gtk_widget_get_state (widget),
+ widget,
+ "statusbar",
+ get_grip_edge (widget),
+ 0, 0,
+ rect.width, rect.height);
+ cairo_restore (cr);
+ }
+
+ return ret;
}
/**
if (gtk_widget_get_realized (widget) && priv->frame)
{
- gtk_widget_get_allocation (widget, &allocation);
+ gint width, height;
+ gtk_widget_get_allocation (widget, &allocation);
- gint width = allocation.width + left + right;
- gint height = allocation.height + top + bottom;
+ width = allocation.width + left + right;
+ height = allocation.height + top + bottom;
gdk_window_resize (priv->frame, width, height);
gtk_decorated_window_move_resize_window (window,
left, top,
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");
+ }
}
/**
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);
_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)
{
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"
{
g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
- return gdk_visual_get_screen (window->priv->visual);
+ return window->priv->screen;
}
/**
* 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);
{
gint result, x = 0, y = 0;
guint w, h;
+ GtkWidget *child;
GdkGravity grav;
gboolean size_set, pos_set;
GdkScreen *screen;
g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
g_return_val_if_fail (geometry != NULL, FALSE);
+ 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);