Commit e86c5323 authored by Jasper St. Pierre's avatar Jasper St. Pierre
Browse files

display: Move the pointer event handling code to work in terms of Clutter events



There is now a meta_display_handle_event alongside the
meta_display_handle_xevent function which handles events in terms of
Clutter events instead of X events. A Clutter event filter is
registered so that all Clutter events will pass through this function.
The pointer event handling code from the X event version has been moved
into this new function and has been modified to use the details from
the Clutter event instead of the X event. This is a step towards
moving all of the event handling code over to use Clutter events.
Based-heavily-on-a-patch-by: default avatarNeil Roberts <neil@linux.intel.com>
parent 4ea4658a
......@@ -39,6 +39,7 @@
#include "keybindings-private.h"
#include <meta/prefs.h>
#include <meta/barrier.h>
#include <clutter/clutter.h>
#ifdef HAVE_STARTUP_NOTIFICATION
#include <libsn/sn.h>
......@@ -189,7 +190,7 @@ struct _MetaDisplay
MetaWindow* autoraise_window;
/* Alt+click button grabs */
unsigned int window_grab_modifiers;
ClutterModifierType window_grab_modifiers;
/* current window operation */
MetaGrabOp grab_op;
......@@ -485,6 +486,9 @@ guint meta_display_get_above_tab_keycode (MetaDisplay *display);
gboolean meta_display_handle_xevent (MetaDisplay *display,
XEvent *event);
gboolean meta_display_handle_event (MetaDisplay *display,
const ClutterEvent *event);
#ifdef HAVE_XI23
gboolean meta_display_process_barrier_event (MetaDisplay *display,
XIEvent *event);
......
......@@ -174,8 +174,10 @@ static void meta_spew_event (MetaDisplay *display,
XEvent *event);
#endif
static gboolean event_callback (XEvent *event,
static gboolean xevent_callback (XEvent *event,
gpointer data);
static gboolean event_callback (const ClutterEvent *event,
gpointer data);
static Window event_get_modified_window (MetaDisplay *display,
XEvent *event);
static Window xievent_get_modified_window (MetaDisplay *display,
......@@ -603,8 +605,9 @@ meta_display_open (void)
/* Get events */
meta_ui_add_event_func (the_display->xdisplay,
event_callback,
xevent_callback,
the_display);
clutter_event_add_filter (event_callback, the_display);
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
meta_unsigned_long_equal);
......@@ -1134,8 +1137,9 @@ meta_display_close (MetaDisplay *display,
/* Stop caring about events */
meta_ui_remove_event_func (display->xdisplay,
event_callback,
xevent_callback,
display);
clutter_event_remove_filter (event_callback, display);
/* Free all screens */
tmp = display->screens;
......@@ -1866,6 +1870,32 @@ handle_net_restack_window (MetaDisplay* display,
}
#endif
static MetaWindow *
get_window_for_actor (ClutterActor *actor,
gboolean *frame_was_receiver)
{
/* Look for any ancestor that is a MetaWindowActor to determine
which window the actor's event belongs to */
*frame_was_receiver = TRUE;
while (actor)
{
if (META_IS_WINDOW_ACTOR (actor))
return meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
/* If the frame is the receiver then the source will directly be
the MetaWindowActor, otherwise it will be a child of a
MetaWindowActor so if we make it here then the event isn't
referring to the frame. */
*frame_was_receiver = FALSE;
actor = clutter_actor_get_parent (actor);
}
return NULL;
}
static XIEvent *
get_input_event (MetaDisplay *display,
XEvent *event)
......@@ -2193,26 +2223,18 @@ handle_window_focus_event (MetaDisplay *display,
}
}
static gboolean
handle_input_xevent (MetaDisplay *display,
XIEvent *input_event,
gulong serial)
gboolean
meta_display_handle_event (MetaDisplay *display,
const ClutterEvent *event)
{
XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
Window modified;
MetaWindow *window;
gboolean frame_was_receiver;
if (input_event == NULL)
return FALSE;
window = get_window_for_actor (event->any.source, &frame_was_receiver);
modified = xievent_get_modified_window (display, input_event);
window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
frame_was_receiver = (window && window->frame && modified == window->frame->xwindow);
display->current_time = event->any.time;
if (window && !window->override_redirect &&
((input_event->type == XI_KeyPress) || (input_event->type == XI_ButtonPress)))
if (window && !window->override_redirect && event->type == CLUTTER_BUTTON_PRESS)
{
if (CurrentTime == display->current_time)
{
......@@ -2231,34 +2253,18 @@ handle_input_xevent (MetaDisplay *display,
}
}
switch (input_event->evtype)
switch (event->type)
{
case XI_KeyPress:
case XI_KeyRelease:
/* For key events, it's important to enforce single-handling, or
* we can get into a confused state. So if a keybinding is
* handled (because it's one of our hot-keys, or because we are
* in a keyboard-grabbed mode like moving a window, we don't
* want to pass the key event to the compositor or GTK+ at all.
*/
if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
return TRUE;
break;
case XI_ButtonPress:
case CLUTTER_BUTTON_PRESS:
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 &&
(event->button.modifier_state & display->window_grab_modifiers) &&
display->grab_button != (int) event->button.button &&
display->grab_window == window) ||
grab_op_is_keyboard (display->grab_op))
{
......@@ -2270,38 +2276,39 @@ handle_input_xevent (MetaDisplay *display,
"none"));
if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
{
MetaScreen *screen;
meta_topic (META_DEBUG_WINDOW_OPS,
"Syncing to old stack positions.\n");
screen =
meta_display_screen_for_root (display, device_event->event);
if (screen!=NULL)
meta_stack_set_positions (screen->stack,
/* XXX: I'm not sure if this is the right thing to do.
The pre-Wayland code was only calling
meta_stack_set_positions if the modified window was a
root window */
if (event->any.source == CLUTTER_ACTOR (event->any.stage) && window && window->screen)
meta_stack_set_positions (window->screen->stack,
display->grab_old_window_stacking);
}
meta_display_end_grab_op (display,
device_event->time);
event->any.time);
}
else if (window && display->grab_op == META_GRAB_OP_NONE)
{
gboolean begin_move = FALSE;
unsigned int grab_mask;
ClutterModifierType grab_mask;
gboolean unmodified;
grab_mask = display->window_grab_modifiers;
if (g_getenv ("MUTTER_DEBUG_BUTTON_GRABS"))
grab_mask |= ControlMask;
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.
*/
unmodified = (device_event->mods.effective & grab_mask) == 0;
unmodified = (event->button.modifier_state & grab_mask) == 0;
if (unmodified ||
device_event->detail == 1)
event->button.button == 1)
{
/* don't focus if frame received, will be lowered in
* frames.c or special-cased if the click was on a
......@@ -2322,8 +2329,8 @@ handle_input_xevent (MetaDisplay *display,
{
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);
window->desc, event->button.button);
meta_window_focus (window, event->any.time);
}
else
/* However, do allow terminals to lose focus due to new
......@@ -2338,7 +2345,7 @@ handle_input_xevent (MetaDisplay *display,
if (!unmodified)
begin_move = TRUE;
}
else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
else if (!unmodified && ((int) event->button.button == meta_prefs_get_mouse_button_resize ()))
{
if (window->has_resize_func)
{
......@@ -2349,10 +2356,10 @@ handle_input_xevent (MetaDisplay *display,
meta_window_get_position (window, &root_x, &root_y);
west = device_event->root_x < (root_x + 1 * window->rect.width / 3);
east = device_event->root_x > (root_x + 2 * window->rect.width / 3);
north = device_event->root_y < (root_y + 1 * window->rect.height / 3);
south = device_event->root_y > (root_y + 2 * window->rect.height / 3);
west = event->button.x < (root_x + 1 * window->rect.width / 3);
east = event->button.x > (root_x + 2 * window->rect.width / 3);
north = event->button.y < (root_y + 1 * window->rect.height / 3);
south = event->button.y > (root_y + 2 * window->rect.height / 3);
if (north && west)
op = META_GRAB_OP_RESIZING_NW;
......@@ -2380,22 +2387,22 @@ handle_input_xevent (MetaDisplay *display,
op,
TRUE,
FALSE,
device_event->detail,
event->button.button,
0,
device_event->time,
device_event->root_x,
device_event->root_y);
event->any.time,
event->button.x,
event->button.y);
}
}
else if (device_event->detail == meta_prefs_get_mouse_button_menu())
else if ((int) event->button.button == 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);
event->button.x,
event->button.y,
event->button.button,
event->any.time);
}
if (!frame_was_receiver && unmodified)
......@@ -2405,10 +2412,11 @@ handle_input_xevent (MetaDisplay *display,
*/
meta_verbose ("Allowing events time %u\n",
(unsigned int)device_event->time);
(unsigned int) event->any.time);
XIAllowEvents (display->xdisplay, device_event->deviceid,
XIReplayDevice, device_event->time);
/* XXX -- implement this in Wayland */
XIAllowEvents (display->xdisplay, META_VIRTUAL_CORE_POINTER_ID,
XIReplayDevice, event->any.time);
}
if (begin_move && window->has_move_func)
......@@ -2419,15 +2427,15 @@ handle_input_xevent (MetaDisplay *display,
META_GRAB_OP_MOVING,
TRUE,
FALSE,
device_event->detail,
event->button.button,
0,
device_event->time,
device_event->root_x,
device_event->root_y);
event->any.time,
event->button.x,
event->button.y);
}
}
break;
case XI_ButtonRelease:
case CLUTTER_BUTTON_RELEASE:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
break;
......@@ -2435,15 +2443,71 @@ handle_input_xevent (MetaDisplay *display,
if (display->grab_window == window &&
meta_grab_op_is_mouse (display->grab_op))
meta_window_handle_mouse_grab_op_event (window, device_event);
meta_window_handle_mouse_grab_op_event (window, event);
break;
case XI_Motion:
case CLUTTER_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_event (window, device_event);
meta_window_handle_mouse_grab_op_event (window, event);
break;
default:
break;
}
return FALSE;
}
static gboolean
handle_input_xevent (MetaDisplay *display,
XIEvent *input_event,
gulong serial)
{
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
Window modified;
MetaWindow *window;
if (input_event == NULL)
return FALSE;
modified = xievent_get_modified_window (display, input_event);
window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
if (window && !window->override_redirect && input_event->type == XI_KeyPress)
{
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_KeyPress:
case XI_KeyRelease:
/* For key events, it's important to enforce single-handling, or
* we can get into a confused state. So if a keybinding is
* handled (because it's one of our hot-keys, or because we are
* in a keyboard-grabbed mode like moving a window, we don't
* want to pass the key event to the compositor or GTK+ at all.
*/
if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
return TRUE;
break;
case XI_Enter:
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
......@@ -3251,8 +3315,8 @@ meta_display_handle_xevent (MetaDisplay *display,
}
static gboolean
event_callback (XEvent *event,
gpointer data)
xevent_callback (XEvent *event,
gpointer data)
{
MetaDisplay *display = data;
......@@ -3274,6 +3338,15 @@ event_callback (XEvent *event,
return meta_display_handle_xevent (display, event);
}
static gboolean
event_callback (const ClutterEvent *event,
gpointer data)
{
MetaDisplay *display = data;
return meta_display_handle_event (display, event);
}
static Window
xievent_get_modified_window (MetaDisplay *display,
XIEvent *input_event)
......
......@@ -44,6 +44,7 @@
#include <X11/Xutil.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
#include "meta-wayland-types.h"
typedef struct _MetaWindowQueue MetaWindowQueue;
......@@ -642,8 +643,8 @@ void meta_window_update_sync_request_counter (MetaWindow *window,
gint64 new_counter_value);
#endif /* HAVE_XSYNC */
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
XIDeviceEvent *xev);
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
const ClutterEvent *event);
GList* meta_window_get_workspaces (MetaWindow *window);
......
......@@ -63,6 +63,7 @@
#include <X11/extensions/Xcomposite.h>
#include "meta-wayland-private.h"
#include "meta/compositor-mutter.h"
/* Windows that unmaximize to a size bigger than that fraction of the workarea
* will be scaled down to that size (while maintaining aspect ratio).
......@@ -9899,96 +9900,20 @@ update_resize (MetaWindow *window,
g_get_current_time (&window->display->grab_last_moveresize_time);
}
typedef struct
{
Window window;
int count;
guint32 last_time;
} EventScannerData;
static Bool
find_last_time_predicate (Display *display,
XEvent *ev,
XPointer arg)
{
EventScannerData *esd = (void*) arg;
XIEvent *xev;
if (ev->type != GenericEvent)
return False;
/* We are peeking into events not yet handled by GDK,
* Allocate cookie events here so we can handle XI2.
*
* GDK will handle later these events, and eventually
* free the cookie data itself.
*/
XGetEventData (display, &ev->xcookie);
xev = (XIEvent *) ev->xcookie.data;
if (xev->evtype != XI_Motion)
return False;
if (esd->window != ((XIDeviceEvent *) xev)->event)
return False;
esd->count += 1;
esd->last_time = xev->time;
return False;
}
static gboolean
check_use_this_motion_notify (MetaWindow *window,
XIDeviceEvent *xev)
{
EventScannerData esd;
XEvent useless;
/* This code is copied from Owen's GDK code. */
if (window->display->grab_motion_notify_time != 0)
{
/* == is really the right test, but I'm all for paranoia */
if (window->display->grab_motion_notify_time <=
xev->time)
{
meta_topic (META_DEBUG_RESIZING,
"Arrived at event with time %u (waiting for %u), using it\n",
(unsigned int)xev->time,
window->display->grab_motion_notify_time);
window->display->grab_motion_notify_time = 0;
return TRUE;
}
else
return FALSE; /* haven't reached the saved timestamp yet */
}
esd.window = xev->event;
esd.count = 0;
esd.last_time = 0;
/* "useless" isn't filled in because the predicate never returns True */
XCheckIfEvent (window->display->xdisplay,
&useless,
find_last_time_predicate,
(XPointer) &esd);
if (esd.count > 0)
meta_topic (META_DEBUG_RESIZING,
"Will skip %d motion events and use the event with time %u\n",
esd.count, (unsigned int) esd.last_time);
if (esd.last_time == 0)
return TRUE;
else
{
/* Save this timestamp, and ignore all motion notify
* until we get to the one with this stamp.
*/
window->display->grab_motion_notify_time = esd.last_time;
return FALSE;
}
check_use_this_motion_notify (MetaWindow *window,
const ClutterEvent *event)
{
/* XXX: Previously this code would walk through the X event queue
and filter out motion events that are followed by a later motion
event. There currently isn't any API to do the equivalent
procedure with the Clutter event queue so this function does
nothing. Clutter does its own motion event squashing so it may be
the case that this function isn't necessary. If it turns out that
we do need additional motion event squashing we could add some
extra API to the Clutter event queue and implement this function
properly. */
return TRUE;
}
static void
......@@ -10062,17 +9987,23 @@ meta_window_update_sync_request_counter (MetaWindow *window,
#endif /* HAVE_XSYNC */
void
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
XIDeviceEvent *xev)
meta_window_handle_mouse_grab_op_event (MetaWindow *window,
const ClutterEvent *event)
{
switch (xev->evtype)
gboolean is_window_root = (event->any.stage != NULL &&
window &&
window->screen &&
CLUTTER_ACTOR (event->any.stage) ==
meta_get_stage_for_screen (window->screen));
switch (event->type)
{
case XI_ButtonRelease:
if (xev->detail == 1)
case CLUTTER_BUTTON_RELEASE:
if (event->button.button == 1)
{
meta_display_check_threshold_reached (window->display,
xev->root_x,
xev->root_y);
event->button.x,
event->button.y);
/* If the user was snap moving then ignore the button
* release because they may have let go of shift before
* releasing the mouse button and they almost certainly do
......@@ -10085,19 +10016,19 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,
{
if (window->tile_mode != META_TILE_NONE)
meta_window_tile (window);
else if (xev->root == window->screen->xroot)
else if (is_window_root)
update_move (window,
xev->mods.effective & ShiftMask,
xev->root_x,
xev->root_y);
event->button.modifier_state & CLUTTER_SHIFT_MASK,
event->button.x,
event->button.y);
}
else if (meta_grab_op_is_resizing (window->display->grab_op))
{
if (xev->root == window->screen->xroot)
if (is_window_root)
update_resize (window,
xev->mods.effective & ShiftMask,
xev->root_x,
xev->root_y,
event->button.modifier_state & CLUTTER_SHIFT_MASK,
event->button.x,
event->button.y,
TRUE);
/* If a tiled window has been dragged free with a
......@@ -10109,37 +10040,36 @@ meta_window_handle_mouse_grab_op_event (MetaWindow *window,