diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index bb2092f0d..684a953dc 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -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; diff --git a/src/core/display.c b/src/core/display.c index 9c1e72d1b..3631eebf0 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -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 middle) + * - on move button, with modifiers => start an interactive move + * (normally left) + * - on menu button, with modifiers => show the window menu + * (normally 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;