Allow windows to be dragged by clicking on empty areas

Allow windows to be dragged by clicking on empty areas in menubars
and toolbars. This is under theme control, via the GtkWidget::window-dragging
style property. The idea is that it makes sense to turn this on if a
theme makes the window frame and the menubar/toolbar appear visually
contiguous.

The main patch was written by Cody Russell, with a contribution by
Ayan George. See bug 611313.
This commit is contained in:
Matthias Clasen
2010-07-16 01:15:47 -04:00
parent 89d0955431
commit 7491e9e97a
4 changed files with 231 additions and 44 deletions

View File

@ -596,14 +596,19 @@ gtk_menu_shell_button_press (GtkWidget *widget,
if (!menu_shell->active || !menu_shell->button)
{
_gtk_menu_shell_activate (menu_shell);
gboolean initially_active = menu_shell->active;
menu_shell->button = event->button;
if (menu_item && _gtk_menu_item_is_selectable (menu_item) &&
if (menu_item)
{
if (_gtk_menu_item_is_selectable (menu_item) &&
menu_item->parent == widget &&
menu_item != menu_shell->active_menu_item)
{
_gtk_menu_shell_activate (menu_shell);
menu_shell->button = event->button;
if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
{
menu_shell->activate_time = event->time;
@ -611,6 +616,28 @@ gtk_menu_shell_button_press (GtkWidget *widget,
}
}
}
else
{
if (!initially_active)
{
gboolean window_drag = FALSE;
gtk_widget_style_get (widget,
"window-dragging", &window_drag,
NULL);
if (window_drag)
{
gtk_menu_shell_deactivate (menu_shell);
gtk_window_begin_move_drag (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
event->button,
event->x_root,
event->y_root,
event->time);
}
}
}
}
else
{
widget = gtk_get_event_widget ((GdkEvent*) event);

View File

@ -44,11 +44,11 @@
* Use gtk_separator_tool_item_new() to create a new #GtkSeparatorToolItem.
*/
#define MENU_ID "gtk-separator-tool-item-menu-id"
struct _GtkSeparatorToolItemPrivate
{
GdkWindow *event_window;
guint draw : 1;
};
@ -68,11 +68,19 @@ static void gtk_separator_tool_item_get_property (GObject
GParamSpec *pspec);
static void gtk_separator_tool_item_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_separator_tool_item_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_separator_tool_item_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_separator_tool_item_add (GtkContainer *container,
GtkWidget *child);
static gint get_space_size (GtkToolItem *tool_item);
static void gtk_separator_tool_item_realize (GtkWidget *widget);
static void gtk_separator_tool_item_unrealize (GtkWidget *widget);
static void gtk_separator_tool_item_map (GtkWidget *widget);
static void gtk_separator_tool_item_unmap (GtkWidget *widget);
static gboolean gtk_separator_tool_item_button_event (GtkWidget *widget,
GdkEventButton *event);
G_DEFINE_TYPE (GtkSeparatorToolItem, gtk_separator_tool_item, GTK_TYPE_TOOL_ITEM)
@ -109,7 +117,15 @@ gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass *class)
object_class->set_property = gtk_separator_tool_item_set_property;
object_class->get_property = gtk_separator_tool_item_get_property;
widget_class->size_request = gtk_separator_tool_item_size_request;
widget_class->size_allocate = gtk_separator_tool_item_size_allocate;
widget_class->expose_event = gtk_separator_tool_item_expose;
widget_class->realize = gtk_separator_tool_item_realize;
widget_class->unrealize = gtk_separator_tool_item_unrealize;
widget_class->map = gtk_separator_tool_item_map;
widget_class->unmap = gtk_separator_tool_item_unmap;
widget_class->button_press_event = gtk_separator_tool_item_button_event;
widget_class->button_release_event = gtk_separator_tool_item_button_event;
toolitem_class->create_menu_proxy = gtk_separator_tool_item_create_menu_proxy;
container_class->add = gtk_separator_tool_item_add;
@ -122,6 +138,7 @@ gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass *class)
TRUE,
GTK_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkSeparatorToolItemPrivate));
}
@ -132,6 +149,8 @@ gtk_separator_tool_item_init (GtkSeparatorToolItem *separator_item)
GTK_TYPE_SEPARATOR_TOOL_ITEM,
GtkSeparatorToolItemPrivate);
separator_item->priv->draw = TRUE;
gtk_widget_set_has_window (GTK_WIDGET (separator_item), FALSE);
}
static void
@ -210,6 +229,116 @@ gtk_separator_tool_item_size_request (GtkWidget *widget,
}
}
static void
gtk_separator_tool_item_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
GtkSeparatorToolItemPrivate *priv = separator->priv;
widget->allocation = *allocation;
if (gtk_widget_get_realized (widget))
gdk_window_move_resize (priv->event_window,
widget->allocation.x,
widget->allocation.y,
widget->allocation.width,
widget->allocation.height);
}
static void
gtk_separator_tool_item_realize (GtkWidget *widget)
{
GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
GtkSeparatorToolItemPrivate *priv = separator->priv;
GdkWindowAttr attributes;
gint attributes_mask;
gtk_widget_set_realized (widget, TRUE);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = widget->allocation.x;
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
attributes.wclass = GDK_INPUT_ONLY;
attributes.visual = gtk_widget_get_visual (widget);
attributes.colormap = gtk_widget_get_colormap (widget);
attributes.event_mask = gtk_widget_get_events (widget) |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y;
widget->window = gtk_widget_get_parent_window (widget);
g_object_ref (widget->window);
priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
gdk_window_set_user_data (priv->event_window, widget);
widget->style = gtk_style_attach (widget->style, widget->window);
}
static void
gtk_separator_tool_item_unrealize (GtkWidget *widget)
{
GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
GtkSeparatorToolItemPrivate *priv = separator->priv;
if (priv->event_window)
{
gdk_window_set_user_data (priv->event_window, NULL);
gdk_window_destroy (priv->event_window);
priv->event_window = NULL;
}
GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unrealize (widget);
}
static void
gtk_separator_tool_item_map (GtkWidget *widget)
{
GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
GtkSeparatorToolItemPrivate *priv = separator->priv;
GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->map (widget);
if (priv->event_window)
gdk_window_show (priv->event_window);
}
static void
gtk_separator_tool_item_unmap (GtkWidget *widget)
{
GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
GtkSeparatorToolItemPrivate *priv = separator->priv;
if (priv->event_window)
gdk_window_hide (priv->event_window);
GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unmap (widget);
}
static gboolean
gtk_separator_tool_item_button_event (GtkWidget *widget,
GdkEventButton *event)
{
GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
GtkSeparatorToolItemPrivate *priv = separator->priv;
/* We want window dragging to work on empty toolbar areas,
* so we only eat button events on visible separators
*/
return priv->draw;
}
#define DEFAULT_SPACE_SIZE 12
#define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
#define SPACE_LINE_DIVISION 10.0
#define SPACE_LINE_START 2.0
#define SPACE_LINE_END 8.0
static gboolean
gtk_separator_tool_item_expose (GtkWidget *widget,
GdkEventExpose *event)

View File

@ -2630,6 +2630,8 @@ static gboolean
gtk_toolbar_button_press (GtkWidget *toolbar,
GdkEventButton *event)
{
GtkWidget *window;
if (event->button == 3)
{
gboolean return_value;
@ -2641,6 +2643,28 @@ gtk_toolbar_button_press (GtkWidget *toolbar,
return return_value;
}
window = gtk_widget_get_toplevel (toolbar);
if (window)
{
gboolean window_drag = FALSE;
gtk_widget_style_get (toolbar,
"window-dragging", &window_drag,
NULL);
if (window_drag)
{
gtk_window_begin_move_drag (GTK_WINDOW (window),
event->button,
event->x_root,
event->y_root,
event->time);
return TRUE;
}
}
return FALSE;
}

View File

@ -2491,6 +2491,13 @@ gtk_widget_class_init (GtkWidgetClass *klass)
0.0, 1.0, 0.04,
GTK_PARAM_READABLE));
gtk_widget_class_install_style_property (klass,
g_param_spec_boolean ("window-dragging",
P_("Window dragging"),
P_("Whether windows can be dragged by clicking on empty areas"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkWidget:draw-border:
*