+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;
+}
+