[gtk+/resizegrips] Initial attempt at generic resize grips
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/resizegrips] Initial attempt at generic resize grips
- Date: Tue, 28 Sep 2010 02:43:06 +0000 (UTC)
commit 9e9e76862b9880e5aed8b31eeaae13a5766e4055
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Sep 27 22:41:24 2010 -0400
Initial attempt at generic resize grips
gtk/gtkwindow.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 259 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index b663636..6f97950 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -104,6 +104,9 @@ struct _GtkWindowPrivate
gdouble opacity;
+ gboolean has_resize_grip;
+ GdkWindow *grip_window;
+
gchar *startup_id;
gchar *title;
gchar *wmclass_class;
@@ -201,7 +204,8 @@ enum {
PROP_GRAVITY,
PROP_TRANSIENT_FOR,
PROP_OPACITY,
-
+ PROP_HAS_RESIZE_GRIP,
+
/* Readonly properties */
PROP_IS_ACTIVE,
PROP_HAS_TOPLEVEL_FOCUS,
@@ -307,6 +311,8 @@ 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,
@@ -379,6 +385,11 @@ 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 get_grip_rect (GtkWindow *window,
+ GdkRectangle *rect);
+static void gtk_window_set_has_resize_grip (GtkWindow *window,
+ gboolean value);
+static void resize_grip_create_window (GtkWindow *window);
static void gtk_window_notify_keys_changed (GtkWindow *window);
static GtkKeyHash *gtk_window_get_key_hash (GtkWindow *window);
@@ -542,6 +553,7 @@ 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;
@@ -819,6 +831,21 @@ gtk_window_class_init (GtkWindowClass *klass)
TRUE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkWindow:has-resize-grip
+ *
+ * Whether the window should have a corner resize grip.
+ *
+ * Since: 2.20
+ */
+ 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:gravity:
@@ -1026,6 +1053,7 @@ 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);
@@ -1046,7 +1074,7 @@ gtk_window_set_property (GObject *object,
{
GtkWindow *window = GTK_WINDOW (object);
GtkWindowPrivate *priv = window->priv;
-
+
switch (prop_id)
{
case PROP_TYPE:
@@ -1060,7 +1088,7 @@ 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));
@@ -1136,6 +1164,8 @@ 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));
case PROP_MNEMONICS_VISIBLE:
gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
break;
@@ -1248,6 +1278,8 @@ 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);
case PROP_MNEMONICS_VISIBLE:
g_value_set_boolean (value, priv->mnemonics_visible);
break;
@@ -4540,6 +4572,9 @@ gtk_window_map (GtkWidget *widget)
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? */
@@ -4591,7 +4626,7 @@ gtk_window_unmap (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
- GtkWindowGeometryInfo *info;
+ GtkWindowGeometryInfo *info;
GdkWindow *gdk_window;
GdkWindowState state;
@@ -4603,6 +4638,9 @@ gtk_window_unmap (GtkWidget *widget)
else
gdk_window_withdraw (gdk_window);
+ if (priv->grip_window)
+ gdk_window_hide (priv->grip_window);
+
priv->configure_request_count = 0;
priv->configure_notify_received = FALSE;
@@ -4814,6 +4852,9 @@ gtk_window_realize (GtkWidget *widget)
/* Icons */
gtk_window_realize_icon (window);
+
+ if (priv->has_resize_grip)
+ resize_grip_create_window (window);
}
static void
@@ -4856,6 +4897,44 @@ gtk_window_unrealize (GtkWidget *widget)
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 void
+set_grip_cursor (GtkWindow *window)
+{
+ GtkWindowPrivate *priv = window->priv;
+
+ if (priv->has_resize_grip && priv->grip_window != NULL)
+ {
+ GtkWidget *widget = GTK_WIDGET (window);
+ GdkDisplay *display;
+ GdkWindowEdge edge;
+ GdkCursorType cursor_type;
+ GdkCursor *cursor;
+
+ if (gtk_widget_is_sensitive (widget))
+ {
+ display = gtk_widget_get_display (widget);
+ edge = get_grip_edge (widget);
+
+ if (edge == GDK_WINDOW_EDGE_SOUTH_EAST)
+ cursor_type = GDK_BOTTOM_RIGHT_CORNER;
+ else
+ cursor_type = GDK_BOTTOM_LEFT_CORNER;
+
+ 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
gtk_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@@ -4888,6 +4967,19 @@ gtk_window_size_allocate (GtkWidget *widget,
allocation->width + priv->frame_left + priv->frame_right,
allocation->height + priv->frame_top + priv->frame_bottom);
}
+
+ if (priv->grip_window != NULL)
+ {
+ GdkRectangle rect;
+
+ get_grip_rect (window, &rect);
+
+ gdk_window_move_resize (priv->grip_window,
+ rect.x, rect.y,
+ rect.width, rect.height);
+
+ set_grip_cursor (window);
+ }
}
static gint
@@ -5008,11 +5100,130 @@ 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 void
+get_grip_rect (GtkWindow *window,
+ GdkRectangle *rect)
+{
+ GtkWidget *widget;
+ GtkAllocation allocation;
+ GtkStyle *style;
+ gint w, h;
+
+ widget = GTK_WIDGET (window);
+ gtk_widget_get_allocation (widget, &allocation);
+ style = gtk_widget_get_style (widget);
+
+ /* These are in effect the max/default size of the grip. */
+ w = 18;
+ h = 18;
+
+ if (w > allocation.width)
+ w = allocation.width;
+
+ if (h > allocation.height - style->ythickness)
+ h = allocation.height - style->ythickness;
+
+ rect->width = w;
+ rect->height = h;
+ rect->y = allocation.y + allocation.height - h;
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ rect->x = allocation.x + allocation.width - w;
+ else
+ rect->x = allocation.x + style->xthickness;
+}
+
+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);
+
+ get_grip_rect (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_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget) | 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_cursor (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;
+}
+
+static 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_resize (statusbar->label); // XXX
+ 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);
+
+ if (gtk_widget_get_mapped (widget))
+ {
+ gdk_window_show (priv->grip_window);
+ }
+ }
+ else if (!priv->has_resize_grip && priv->grip_window != NULL)
+ {
+ resize_grip_destroy_window (window);
+ }
+ }
+
+ g_object_notify (G_OBJECT (priv), "has-resize-grip");
+ }
+}
+
/* 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
@@ -5151,6 +5362,25 @@ 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;
+
+ if (event->window == priv->grip_window)
+ {
+ gtk_window_begin_resize_drag (GTK_WINDOW (widget),
+ get_grip_edge (widget),
+ event->button,
+ event->x_root,
+ event->y_root,
+ event->time);
+ }
+
+ return FALSE;
+}
+
static void
gtk_window_real_activate_default (GtkWindow *window)
{
@@ -6652,7 +6882,10 @@ static gboolean
gtk_window_draw (GtkWidget *widget,
cairo_t *cr)
{
- if (!gtk_widget_get_app_paintable (widget))
+ 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,
GTK_STATE_NORMAL,
@@ -6660,11 +6893,29 @@ gtk_window_draw (GtkWidget *widget,
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->has_resize_grip)
+ {
+ GdkRectangle rect;
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ get_grip_rect (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),
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ return ret;
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]