display: move more event handling to clutter

Mouse event handling was duplicated, resulting in weird interactions
if clutter was allowed to see certain events (for example under
wayland, where it gets all events). Because now clutter sees all
X events, even when running as an x11 compositor, we can handle
everything using the clutter variants.
At the same time, rewrite a little the passive button grab code,
to make it clear what is being matched on what and why.
This commit is contained in:
Giovanni Campagna 2014-02-27 00:51:07 +01:00
parent 360d423faa
commit b00fa70d91
2 changed files with 95 additions and 299 deletions

View File

@ -953,6 +953,29 @@ meta_compositor_window_surface_changed (MetaCompositor *compositor,
meta_window_actor_update_surface (window_actor);
}
static gboolean
grab_op_is_clicking (MetaGrabOp grab_op)
{
switch (grab_op)
{
case META_GRAB_OP_CLICKING_MINIMIZE:
case META_GRAB_OP_CLICKING_MAXIMIZE:
case META_GRAB_OP_CLICKING_UNMAXIMIZE:
case META_GRAB_OP_CLICKING_DELETE:
case META_GRAB_OP_CLICKING_MENU:
case META_GRAB_OP_CLICKING_SHADE:
case META_GRAB_OP_CLICKING_UNSHADE:
case META_GRAB_OP_CLICKING_ABOVE:
case META_GRAB_OP_CLICKING_UNABOVE:
case META_GRAB_OP_CLICKING_STICK:
case META_GRAB_OP_CLICKING_UNSTICK:
return TRUE;
default:
return FALSE;
}
}
/* Clutter makes the assumption that there is only one X window
* per stage, which is a valid assumption to make for a generic
* application toolkit. As such, it will ignore any events sent
@ -980,8 +1003,10 @@ maybe_spoof_event_as_stage_event (MetaCompScreen *info,
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
/* If this is a window frame, let GTK+ handle it without mangling */
if (window && window->frame && device_event->event == window->frame->xwindow)
/* If this is a window frame, and we think GTK+ needs to handle the event,
let GTK+ handle it without mangling */
if (window && window->frame && device_event->event == window->frame->xwindow &&
(display->grab_op == META_GRAB_OP_NONE || grab_op_is_clicking (display->grab_op)))
break;
case XI_KeyPress:
@ -992,6 +1017,8 @@ maybe_spoof_event_as_stage_event (MetaCompScreen *info,
break;
device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
device_event->event_x = device_event->root_x;
device_event->event_y = device_event->root_y;
break;
default:
break;

View File

@ -2036,9 +2036,6 @@ meta_display_handle_event (MetaDisplay *display,
gboolean bypass_clutter = FALSE, bypass_wayland = FALSE;
MetaWaylandCompositor *compositor = NULL;
/* XXX -- we need to fill this in properly at some point... */
gboolean frame_was_receiver = FALSE;
if (meta_is_wayland_compositor ())
{
compositor = meta_wayland_compositor_get_default ();
@ -2109,60 +2106,70 @@ meta_display_handle_event (MetaDisplay *display,
}
else if (window && display->grab_op == META_GRAB_OP_NONE)
{
gboolean begin_move = FALSE;
ClutterModifierType grab_mask;
gboolean unmodified;
gboolean fully_modified;
grab_mask = display->window_grab_modifiers;
if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
grab_mask |= CLUTTER_CONTROL_MASK;
/* Two possible sources of an unmodified event; one is a
* client that's letting button presses pass through to the
* frame, the other is our focus_window_grab on unmodified
* button 1. So for all such events we focus the window.
/* We have three passive button grabs:
* - on any button, without modifiers => focuses and maybe raises the window
* - on resize button, with modifiers => start an interactive resizing
* (normally <Super>middle)
* - on move button, with modifiers => start an interactive move
* (normally <Super>left)
* - on menu button, with modifiers => show the window menu
* (normally <Super>right)
*
* We may get here because we actually have a button
* grab on the window, or because we're a wayland
* compositor and thus we see all the events, so we
* need to check if the event is interesting.
* We want an event that is not modified, for a window
* that has (or would have, the wayland case) the
* button grab active.
*
* We may have other events on the window, for example
* a click on a frame button, but that's not for us to
* care about. Just let the event through.
*/
unmodified = (event->button.modifier_state & grab_mask) == 0;
fully_modified = (event->button.modifier_state & grab_mask) == grab_mask;
if (unmodified ||
event->button.button == 1)
if (unmodified && window && window->have_focus_click_grab)
{
/* don't focus if frame received, will be lowered in
* frames.c or special-cased if the click was on a
* minimize/close button.
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
else
meta_topic (META_DEBUG_FOCUS,
"Not raising window on click due to don't-raise-on-click option\n");
/* Don't focus panels--they must explicitly request focus.
* See bug 160470
*/
if (!frame_was_receiver)
if (window->type != META_WINDOW_DOCK)
{
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
else
meta_topic (META_DEBUG_FOCUS,
"Not raising window on click due to don't-raise-on-click option\n");
/* Don't focus panels--they must explicitly request focus.
* See bug 160470
*/
if (window->type != META_WINDOW_DOCK)
{
meta_topic (META_DEBUG_FOCUS,
"Focusing %s due to unmodified button %u press (display.c)\n",
window->desc, event->button.button);
meta_window_focus (window, event->any.time);
}
else
/* However, do allow terminals to lose focus due to new
* window mappings after the user clicks on a panel.
*/
display->allow_terminal_deactivation = TRUE;
meta_topic (META_DEBUG_FOCUS,
"Focusing %s due to unmodified button %u press (display.c)\n",
window->desc, event->button.button);
meta_window_focus (window, event->any.time);
}
else
/* However, do allow terminals to lose focus due to new
* window mappings after the user clicks on a panel.
*/
display->allow_terminal_deactivation = TRUE;
/* you can move on alt-click but not on
* the click-to-focus
*/
if (!unmodified)
begin_move = TRUE;
meta_verbose ("Allowing events time %u\n",
(unsigned int)event->button.time);
XIAllowEvents (display->xdisplay, clutter_input_device_get_device_id (event->button.device),
XIReplayDevice, event->button.time);
bypass_clutter = TRUE;
}
else if (!unmodified && ((int) event->button.button == meta_prefs_get_mouse_button_resize ()))
else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_resize ())
{
if (window->has_resize_func)
{
@ -2210,8 +2217,10 @@ meta_display_handle_event (MetaDisplay *display,
event->button.x,
event->button.y);
}
bypass_clutter = TRUE;
bypass_wayland = TRUE;
}
else if ((int) event->button.button == meta_prefs_get_mouse_button_menu ())
else if (fully_modified && (int) event->button.button == meta_prefs_get_mouse_button_menu ())
{
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
@ -2223,20 +2232,22 @@ meta_display_handle_event (MetaDisplay *display,
bypass_clutter = TRUE;
bypass_wayland = TRUE;
}
if (begin_move && window->has_move_func)
else if (fully_modified && (int) event->button.button == 1)
{
meta_display_begin_grab_op (display,
window->screen,
window,
META_GRAB_OP_MOVING,
TRUE,
FALSE,
event->button.button,
0,
event->any.time,
event->button.x,
event->button.y);
if (window->has_move_func)
{
meta_display_begin_grab_op (display,
window->screen,
window,
META_GRAB_OP_MOVING,
TRUE,
FALSE,
event->button.button,
0,
event->any.time,
event->button.x,
event->button.y);
}
bypass_clutter = TRUE;
bypass_wayland = TRUE;
}
@ -2320,250 +2331,8 @@ handle_input_xevent (MetaDisplay *display,
modified = xievent_get_modified_window (display, input_event);
window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
frame_was_receiver = FALSE;
if (window &&
window->frame &&
modified == window->frame->xwindow)
{
/* Note that if the frame and the client both have an
* XGrabButton (as is normal with our setup), the event
* goes to the frame.
*/
frame_was_receiver = TRUE;
meta_topic (META_DEBUG_EVENTS, "Frame was receiver of event for %s\n",
window->desc);
}
if (window && !window->override_redirect &&
(input_event->evtype == XI_KeyPress || input_event->evtype == XI_ButtonPress))
{
if (CurrentTime == display->current_time)
{
/* We can't use missing (i.e. invalid) timestamps to set user time,
* nor do we want to use them to sanity check other timestamps.
* See bug 313490 for more details.
*/
meta_warning ("Event has no timestamp! You may be using a broken "
"program such as xse. Please ask the authors of that "
"program to fix it.\n");
}
else
{
meta_window_set_user_time (window, display->current_time);
sanity_check_timestamps (display, display->current_time);
}
}
switch (input_event->evtype)
{
case XI_ButtonPress:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
break;
display->overlay_key_only_pressed = FALSE;
if (device_event->detail == 4 || device_event->detail == 5)
/* Scrollwheel event, do nothing and deliver event to compositor below */
break;
if ((window &&
meta_grab_op_is_mouse (display->grab_op) &&
(device_event->mods.effective & display->window_grab_modifiers) &&
display->grab_button != device_event->detail &&
display->grab_window == window) ||
grab_op_is_keyboard (display->grab_op))
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Ending grab op %u on window %s due to button press\n",
display->grab_op,
(display->grab_window ?
display->grab_window->desc :
"none"));
if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
{
meta_topic (META_DEBUG_WINDOW_OPS,
"Syncing to old stack positions.\n");
if (device_event->root == device_event->event)
meta_stack_set_positions (screen->stack,
display->grab_old_window_stacking);
}
meta_display_end_grab_op (display,
device_event->time);
}
else if (window && display->grab_op == META_GRAB_OP_NONE)
{
gboolean begin_move = FALSE;
unsigned int grab_mask;
gboolean unmodified;
grab_mask = display->window_grab_modifiers;
if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
grab_mask |= ControlMask;
/* Two possible sources of an unmodified event; one is a
* client that's letting button presses pass through to the
* frame, the other is our focus_window_grab on unmodified
* button 1. So for all such events we focus the window.
*/
unmodified = (device_event->mods.effective & grab_mask) == 0;
if (unmodified ||
device_event->detail == 1)
{
/* don't focus if frame received, will be lowered in
* frames.c or special-cased if the click was on a
* minimize/close button.
*/
if (!frame_was_receiver)
{
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
else
meta_topic (META_DEBUG_FOCUS,
"Not raising window on click due to don't-raise-on-click option\n");
/* Don't focus panels--they must explicitly request focus.
* See bug 160470
*/
if (window->type != META_WINDOW_DOCK)
{
meta_topic (META_DEBUG_FOCUS,
"Focusing %s due to unmodified button %u press (display.c)\n",
window->desc, device_event->detail);
meta_window_focus (window, device_event->time);
}
else
/* However, do allow terminals to lose focus due to new
* window mappings after the user clicks on a panel.
*/
display->allow_terminal_deactivation = TRUE;
}
/* you can move on alt-click but not on
* the click-to-focus
*/
if (!unmodified)
begin_move = TRUE;
}
else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
{
if (window->has_resize_func)
{
gboolean north, south;
gboolean west, east;
MetaRectangle frame_rect;
MetaGrabOp op;
meta_window_get_frame_rect (window, &frame_rect);
west = device_event->root_x < (frame_rect.x + 1 * frame_rect.width / 3);
east = device_event->root_x > (frame_rect.x + 2 * frame_rect.width / 3);
north = device_event->root_y < (frame_rect.y + 1 * frame_rect.height / 3);
south = device_event->root_y > (frame_rect.y + 2 * frame_rect.height / 3);
if (north && west)
op = META_GRAB_OP_RESIZING_NW;
else if (north && east)
op = META_GRAB_OP_RESIZING_NE;
else if (south && west)
op = META_GRAB_OP_RESIZING_SW;
else if (south && east)
op = META_GRAB_OP_RESIZING_SE;
else if (north)
op = META_GRAB_OP_RESIZING_N;
else if (west)
op = META_GRAB_OP_RESIZING_W;
else if (east)
op = META_GRAB_OP_RESIZING_E;
else if (south)
op = META_GRAB_OP_RESIZING_S;
else /* Middle region is no-op to avoid user triggering wrong action */
op = META_GRAB_OP_NONE;
if (op != META_GRAB_OP_NONE)
{
meta_display_begin_grab_op (display,
window->screen,
window,
op,
TRUE,
FALSE,
device_event->detail,
0,
device_event->time,
device_event->root_x,
device_event->root_y);
return TRUE;
}
}
}
else if (device_event->detail == meta_prefs_get_mouse_button_menu())
{
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_show_menu (window,
device_event->root_x,
device_event->root_y,
device_event->detail,
device_event->time);
return TRUE;
}
if (!frame_was_receiver && unmodified)
{
/* This is from our synchronous grab since
* it has no modifiers and was on the client window
*/
meta_verbose ("Allowing events time %u\n",
(unsigned int)device_event->time);
XIAllowEvents (display->xdisplay, device_event->deviceid,
XIReplayDevice, device_event->time);
}
if (begin_move && window->has_move_func)
{
meta_display_begin_grab_op (display,
window->screen,
window,
META_GRAB_OP_MOVING,
TRUE,
FALSE,
device_event->detail,
0,
device_event->time,
device_event->root_x,
device_event->root_y);
return TRUE;
}
}
break;
case XI_ButtonRelease:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
break;
display->overlay_key_only_pressed = FALSE;
if (display->grab_window == window &&
meta_grab_op_is_mouse (display->grab_op))
{
meta_window_handle_mouse_grab_op_xevent (window, device_event);
return TRUE;
}
break;
case XI_Motion:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
break;
if (display->grab_window == window &&
meta_grab_op_is_mouse (display->grab_op))
{
meta_window_handle_mouse_grab_op_xevent (window, device_event);
return TRUE;
}
break;
case XI_Enter:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
break;