Compare commits
	
		
			6 Commits
		
	
	
		
			wip/lantw/
			...
			wip/waylan
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 34398b273c | ||
|   | 00a73c5bdc | ||
|   | 20cd02f086 | ||
|   | 0cb9392686 | ||
|   | 57f0b1d46d | ||
|   | e2d8d886a8 | 
| @@ -52,6 +52,7 @@ libmutter_wayland_la_SOURCES =			\ | |||||||
| 	core/async-getprop.h			\ | 	core/async-getprop.h			\ | ||||||
| 	core/barrier.c				\ | 	core/barrier.c				\ | ||||||
| 	meta/barrier.h				\ | 	meta/barrier.h				\ | ||||||
|  | 	core/barrier-private.h			\ | ||||||
| 	core/bell.c				\ | 	core/bell.c				\ | ||||||
| 	core/bell.h				\ | 	core/bell.h				\ | ||||||
| 	core/boxes.c				\ | 	core/boxes.c				\ | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								src/core/barrier-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/core/barrier-private.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ | ||||||
|  |  | ||||||
|  | /*  | ||||||
|  |  * Copyright 2012, 2013 Red Hat Inc. | ||||||
|  |  *  | ||||||
|  |  * This program is free software; you can redistribute it and/or | ||||||
|  |  * modify it under the terms of the GNU General Public License as | ||||||
|  |  * published by the Free Software Foundation; either version 2 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, but | ||||||
|  |  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
|  |  * General Public License for more details. | ||||||
|  |  *  | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program; if not, write to the Free Software | ||||||
|  |  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||||
|  |  * 02111-1307, USA. | ||||||
|  |  * | ||||||
|  |  * Authors: Jaster St. Pierre <jstpierr@redhat.com> | ||||||
|  |  *          Giovanni Campagna <gcampagn@redhat.com> | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef BARRIER_PRIVATE_H | ||||||
|  | #define BARRIER_PRIVATE_H | ||||||
|  |  | ||||||
|  | typedef struct _MetaBarrierManager MetaBarrierManager; | ||||||
|  |  | ||||||
|  | MetaBarrierManager *meta_barrier_manager_get (void); | ||||||
|  |  | ||||||
|  | void meta_barrier_manager_constrain_cursor (MetaBarrierManager *manager, | ||||||
|  | 					    guint32             time, | ||||||
|  | 					    float               current_x, | ||||||
|  | 					    float               current_y, | ||||||
|  | 					    float              *new_x, | ||||||
|  | 					    float              *new_y); | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -1,5 +1,27 @@ | |||||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ | ||||||
|  |  | ||||||
|  | /*  | ||||||
|  |  * Copyright 2012, 2013 Red Hat Inc. | ||||||
|  |  *  | ||||||
|  |  * This program is free software; you can redistribute it and/or | ||||||
|  |  * modify it under the terms of the GNU General Public License as | ||||||
|  |  * published by the Free Software Foundation; either version 2 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, but | ||||||
|  |  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
|  |  * General Public License for more details. | ||||||
|  |  *  | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program; if not, write to the Free Software | ||||||
|  |  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||||
|  |  * 02111-1307, USA. | ||||||
|  |  * | ||||||
|  |  * Authors: Jaster St. Pierre <jstpierr@redhat.com> | ||||||
|  |  *          Giovanni Campagna <gcampagn@redhat.com> | ||||||
|  |  */ | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * SECTION:barrier |  * SECTION:barrier | ||||||
|  * @Title: MetaBarrier |  * @Title: MetaBarrier | ||||||
| @@ -9,6 +31,7 @@ | |||||||
| #include "config.h" | #include "config.h" | ||||||
|  |  | ||||||
| #include <glib-object.h> | #include <glib-object.h> | ||||||
|  | #include <math.h> | ||||||
|  |  | ||||||
| #include <X11/extensions/XInput2.h> | #include <X11/extensions/XInput2.h> | ||||||
| #include <X11/extensions/Xfixes.h> | #include <X11/extensions/Xfixes.h> | ||||||
| @@ -16,6 +39,7 @@ | |||||||
| #include <meta/barrier.h> | #include <meta/barrier.h> | ||||||
| #include "display-private.h" | #include "display-private.h" | ||||||
| #include "mutter-enum-types.h" | #include "mutter-enum-types.h" | ||||||
|  | #include "barrier-private.h" | ||||||
| #include "core.h" | #include "core.h" | ||||||
|  |  | ||||||
| G_DEFINE_TYPE (MetaBarrier, meta_barrier, G_TYPE_OBJECT) | G_DEFINE_TYPE (MetaBarrier, meta_barrier, G_TYPE_OBJECT) | ||||||
| @@ -56,9 +80,23 @@ struct _MetaBarrierPrivate | |||||||
|  |  | ||||||
|   MetaBarrierDirection directions; |   MetaBarrierDirection directions; | ||||||
|  |  | ||||||
|  |   /* x11 */ | ||||||
|   PointerBarrier xbarrier; |   PointerBarrier xbarrier; | ||||||
|  |  | ||||||
|  |   /* wayland */ | ||||||
|  |   gboolean active; | ||||||
|  |   gboolean seen, hit; | ||||||
|  |  | ||||||
|  |   int barrier_event_id; | ||||||
|  |   int release_event_id; | ||||||
|  |   guint32 last_timestamp; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct _MetaBarrierManager | ||||||
|  | { | ||||||
|  |   GList *barriers; | ||||||
|  | } *global_barrier_manager; | ||||||
|  |  | ||||||
| static void meta_barrier_event_unref (MetaBarrierEvent *event); | static void meta_barrier_event_unref (MetaBarrierEvent *event); | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -148,7 +186,10 @@ meta_barrier_dispose (GObject *object) | |||||||
| gboolean | gboolean | ||||||
| meta_barrier_is_active (MetaBarrier *barrier) | meta_barrier_is_active (MetaBarrier *barrier) | ||||||
| { | { | ||||||
|   return barrier->priv->xbarrier != 0; |   if (meta_is_wayland_compositor ()) | ||||||
|  |     return barrier->priv->active; | ||||||
|  |   else | ||||||
|  |     return barrier->priv->xbarrier != 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -165,15 +206,25 @@ void | |||||||
| meta_barrier_release (MetaBarrier      *barrier, | meta_barrier_release (MetaBarrier      *barrier, | ||||||
|                       MetaBarrierEvent *event) |                       MetaBarrierEvent *event) | ||||||
| { | { | ||||||
| #ifdef HAVE_XI23 |   MetaBarrierPrivate *priv; | ||||||
|   MetaBarrierPrivate *priv = barrier->priv; |  | ||||||
|   if (META_DISPLAY_HAS_XINPUT_23 (priv->display)) |   priv = barrier->priv; | ||||||
|  |  | ||||||
|  |   if (meta_is_wayland_compositor ()) | ||||||
|     { |     { | ||||||
|       XIBarrierReleasePointer (priv->display->xdisplay, |       priv->release_event_id = event->event_id; | ||||||
|                                META_VIRTUAL_CORE_POINTER_ID, |  | ||||||
|                                priv->xbarrier, event->event_id); |  | ||||||
|     } |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  | #ifdef HAVE_XI23 | ||||||
|  |       if (META_DISPLAY_HAS_XINPUT_23 (priv->display)) | ||||||
|  |         { | ||||||
|  |           XIBarrierReleasePointer (priv->display->xdisplay, | ||||||
|  |                                    META_VIRTUAL_CORE_POINTER_ID, | ||||||
|  |                                    priv->xbarrier, event->event_id); | ||||||
|  |         } | ||||||
| #endif /* HAVE_XI23 */ | #endif /* HAVE_XI23 */ | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -192,19 +243,29 @@ meta_barrier_constructed (GObject *object) | |||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   dpy = priv->display->xdisplay; |   if (meta_is_wayland_compositor ()) | ||||||
|   root = DefaultRootWindow (dpy); |     { | ||||||
|  |       MetaBarrierManager *manager = meta_barrier_manager_get (); | ||||||
|  |  | ||||||
|   priv->xbarrier = XFixesCreatePointerBarrier (dpy, root, |       manager->barriers = g_list_prepend (manager->barriers, g_object_ref (barrier)); | ||||||
|                                                priv->x1, priv->y1, |       priv->active = TRUE; | ||||||
|                                                priv->x2, priv->y2, |     } | ||||||
|                                                priv->directions, 0, NULL); |   else | ||||||
|  |     { | ||||||
|  |       dpy = priv->display->xdisplay; | ||||||
|  |       root = DefaultRootWindow (dpy); | ||||||
|  |  | ||||||
|   /* Take a ref that we'll release when the XID dies inside destroy(), |       priv->xbarrier = XFixesCreatePointerBarrier (dpy, root, | ||||||
|    * so that the object stays alive and doesn't get GC'd. */ |                                                    priv->x1, priv->y1, | ||||||
|   g_object_ref (barrier); |                                                    priv->x2, priv->y2, | ||||||
|  |                                                    priv->directions, 0, NULL); | ||||||
|  |  | ||||||
|   g_hash_table_insert (priv->display->xids, &priv->xbarrier, barrier); |       /* Take a ref that we'll release when the XID dies inside destroy(), | ||||||
|  |        * so that the object stays alive and doesn't get GC'd. */ | ||||||
|  |       g_object_ref (barrier); | ||||||
|  |  | ||||||
|  |       g_hash_table_insert (priv->display->xids, &priv->xbarrier, barrier); | ||||||
|  |     } | ||||||
|  |  | ||||||
|   G_OBJECT_CLASS (meta_barrier_parent_class)->constructed (object); |   G_OBJECT_CLASS (meta_barrier_parent_class)->constructed (object); | ||||||
| } | } | ||||||
| @@ -312,16 +373,26 @@ meta_barrier_destroy (MetaBarrier *barrier) | |||||||
|   if (priv->display == NULL) |   if (priv->display == NULL) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   dpy = priv->display->xdisplay; |   if (meta_is_wayland_compositor ()) | ||||||
|  |     { | ||||||
|  |       MetaBarrierManager *manager = meta_barrier_manager_get (); | ||||||
|  |  | ||||||
|   if (!meta_barrier_is_active (barrier)) |       manager->barriers = g_list_remove (manager->barriers, barrier); | ||||||
|     return; |       g_object_unref (barrier); | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       dpy = priv->display->xdisplay; | ||||||
|  |  | ||||||
|   XFixesDestroyPointerBarrier (dpy, priv->xbarrier); |       if (!meta_barrier_is_active (barrier)) | ||||||
|   g_hash_table_remove (priv->display->xids, &priv->xbarrier); |         return; | ||||||
|   priv->xbarrier = 0; |  | ||||||
|  |  | ||||||
|   g_object_unref (barrier); |       XFixesDestroyPointerBarrier (dpy, priv->xbarrier); | ||||||
|  |       g_hash_table_remove (priv->display->xids, &priv->xbarrier); | ||||||
|  |       priv->xbarrier = 0; | ||||||
|  |  | ||||||
|  |       g_object_unref (barrier); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -371,6 +442,9 @@ meta_display_process_barrier_event (MetaDisplay    *display, | |||||||
| { | { | ||||||
|   MetaBarrier *barrier; |   MetaBarrier *barrier; | ||||||
|  |  | ||||||
|  |   if (meta_is_wayland_compositor ()) | ||||||
|  |     return FALSE; | ||||||
|  |  | ||||||
|   barrier = g_hash_table_lookup (display->xids, &xev->barrier); |   barrier = g_hash_table_lookup (display->xids, &xev->barrier); | ||||||
|   if (barrier != NULL) |   if (barrier != NULL) | ||||||
|     { |     { | ||||||
| @@ -382,6 +456,405 @@ meta_display_process_barrier_event (MetaDisplay    *display, | |||||||
| } | } | ||||||
| #endif /* HAVE_XI23 */ | #endif /* HAVE_XI23 */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * The following code was copied and adapted from the X server (Xi/xibarriers.c) | ||||||
|  |  * | ||||||
|  |  * Copyright 2012 Red Hat, Inc. | ||||||
|  |  * Copyright © 2002 Keith Packard | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  |  * copy of this software and associated documentation files (the "Software"), | ||||||
|  |  * to deal in the Software without restriction, including without limitation | ||||||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  |  * Software is furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice (including the next | ||||||
|  |  * paragraph) shall be included in all copies or substantial portions of the | ||||||
|  |  * Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||||
|  |  * DEALINGS IN THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | barrier_is_horizontal(MetaBarrier *barrier) | ||||||
|  | { | ||||||
|  |   return barrier->priv->y1 == barrier->priv->y2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | barrier_is_vertical(MetaBarrier *barrier) | ||||||
|  | { | ||||||
|  |   return barrier->priv->x1 == barrier->priv->x2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * @return The set of barrier movement directions the movement vector | ||||||
|  |  * x1/y1 → x2/y2 represents. | ||||||
|  |  */ | ||||||
|  | static int | ||||||
|  | barrier_get_direction(int x1, int y1, int x2, int y2) | ||||||
|  | { | ||||||
|  |   int direction = 0; | ||||||
|  |  | ||||||
|  |   /* which way are we trying to go */ | ||||||
|  |   if (x2 > x1) | ||||||
|  |     direction |= META_BARRIER_DIRECTION_POSITIVE_X; | ||||||
|  |   if (x2 < x1) | ||||||
|  |     direction |= META_BARRIER_DIRECTION_NEGATIVE_X; | ||||||
|  |   if (y2 > y1) | ||||||
|  |     direction |= META_BARRIER_DIRECTION_POSITIVE_Y; | ||||||
|  |   if (y2 < y1) | ||||||
|  |     direction |= META_BARRIER_DIRECTION_NEGATIVE_Y; | ||||||
|  |  | ||||||
|  |   return direction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Test if the barrier may block movement in the direction defined by | ||||||
|  |  * x1/y1 → x2/y2. This function only tests whether the directions could be | ||||||
|  |  * blocked, it does not test if the barrier actually blocks the movement. | ||||||
|  |  * | ||||||
|  |  * @return TRUE if the barrier blocks the direction of movement or FALSE | ||||||
|  |  * otherwise. | ||||||
|  |  */ | ||||||
|  | static gboolean | ||||||
|  | barrier_is_blocking_direction(MetaBarrier          *barrier, | ||||||
|  |                               MetaBarrierDirection  direction) | ||||||
|  | { | ||||||
|  |   /* Barriers define which way is ok, not which way is blocking */ | ||||||
|  |   return (barrier->priv->directions & direction) != direction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | inside_segment(int v, int v1, int v2) | ||||||
|  | { | ||||||
|  |   if (v1 < 0 && v2 < 0) /* line */ | ||||||
|  |     return TRUE; | ||||||
|  |   else if (v1 < 0)      /* ray */ | ||||||
|  |     return v <= v2; | ||||||
|  |   else if (v2 < 0)      /* ray */ | ||||||
|  |     return v >= v1; | ||||||
|  |   else                  /* line segment */ | ||||||
|  |     return v >= v1 && v <= v2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #define T(v, a, b) (((float)v) - (a)) / ((b) - (a)) | ||||||
|  | #define F(t, a, b) ((t) * ((a) - (b)) + (a)) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Test if the movement vector x1/y1 → x2/y2 is intersecting with the | ||||||
|  |  * barrier. A movement vector with the startpoint or endpoint adjacent to | ||||||
|  |  * the barrier itself counts as intersecting. | ||||||
|  |  * | ||||||
|  |  * @param x1 X start coordinate of movement vector | ||||||
|  |  * @param y1 Y start coordinate of movement vector | ||||||
|  |  * @param x2 X end coordinate of movement vector | ||||||
|  |  * @param y2 Y end coordinate of movement vector | ||||||
|  |  * @param[out] distance The distance between the start point and the | ||||||
|  |  * intersection with the barrier (if applicable). | ||||||
|  |  * @return TRUE if the barrier intersects with the given vector | ||||||
|  |  */ | ||||||
|  | static gboolean | ||||||
|  | barrier_is_blocking(MetaBarrier *barrier, | ||||||
|  |                     int x1, int y1, int x2, int y2, double *distance) | ||||||
|  | { | ||||||
|  |   if (barrier_is_vertical (barrier)) | ||||||
|  |     { | ||||||
|  |       float t, y; | ||||||
|  |       t = T (barrier->priv->x1, x1, x2); | ||||||
|  |       if (t < 0 || t > 1) | ||||||
|  |         return FALSE; | ||||||
|  |  | ||||||
|  |       /* Edge case: moving away from barrier. */ | ||||||
|  |       if (x2 > x1 && t == 0) | ||||||
|  |         return FALSE; | ||||||
|  |  | ||||||
|  |       y = F (t, y1, y2); | ||||||
|  |       if (!inside_segment (y, barrier->priv->y1, barrier->priv->y2)) | ||||||
|  |         return FALSE; | ||||||
|  |  | ||||||
|  |       *distance = sqrt ((y - y1) * (y - y1) + (barrier->priv->x1 - x1) * (barrier->priv->x1 - x1)); | ||||||
|  |       return TRUE; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       float t, x; | ||||||
|  |       t = T (barrier->priv->y1, y1, y2); | ||||||
|  |       if (t < 0 || t > 1) | ||||||
|  |         return FALSE; | ||||||
|  |  | ||||||
|  |       /* Edge case: moving away from barrier. */ | ||||||
|  |       if (y2 > y1 && t == 0) | ||||||
|  |         return FALSE; | ||||||
|  |  | ||||||
|  |       x = F(t, x1, x2); | ||||||
|  |       if (!inside_segment (x, barrier->priv->x1, barrier->priv->x2)) | ||||||
|  |         return FALSE; | ||||||
|  |  | ||||||
|  |       *distance = sqrt ((x - x1) * (x - x1) + (barrier->priv->y1 - y1) * (barrier->priv->y1 - y1)); | ||||||
|  |       return TRUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #define HIT_EDGE_EXTENTS 2 | ||||||
|  | static gboolean | ||||||
|  | barrier_inside_hit_box(MetaBarrier *barrier, int x, int y) | ||||||
|  | { | ||||||
|  |   int x1, x2, y1, y2; | ||||||
|  |   int dir; | ||||||
|  |  | ||||||
|  |   x1 = barrier->priv->x1; | ||||||
|  |   x2 = barrier->priv->x2; | ||||||
|  |   y1 = barrier->priv->y1; | ||||||
|  |   y2 = barrier->priv->y2; | ||||||
|  |   dir = ~(barrier->priv->directions); | ||||||
|  |  | ||||||
|  |   if (barrier_is_vertical (barrier)) | ||||||
|  |     { | ||||||
|  |       if (dir & META_BARRIER_DIRECTION_POSITIVE_X) | ||||||
|  |         x1 -= HIT_EDGE_EXTENTS; | ||||||
|  |       if (dir & META_BARRIER_DIRECTION_NEGATIVE_X) | ||||||
|  |         x2 += HIT_EDGE_EXTENTS; | ||||||
|  |     } | ||||||
|  |   if (barrier_is_horizontal (barrier)) | ||||||
|  |     { | ||||||
|  |       if (dir & META_BARRIER_DIRECTION_POSITIVE_Y) | ||||||
|  |         y1 -= HIT_EDGE_EXTENTS; | ||||||
|  |       if (dir & META_BARRIER_DIRECTION_NEGATIVE_Y) | ||||||
|  |         y2 += HIT_EDGE_EXTENTS; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   return x >= x1 && x <= x2 && y >= y1 && y <= y2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2. | ||||||
|  |  * | ||||||
|  |  * @param dir Only barriers blocking movement in direction dir are checked | ||||||
|  |  * @param x1 X start coordinate of movement vector | ||||||
|  |  * @param y1 Y start coordinate of movement vector | ||||||
|  |  * @param x2 X end coordinate of movement vector | ||||||
|  |  * @param y2 Y end coordinate of movement vector | ||||||
|  |  * @return The barrier nearest to the movement origin that blocks this movement. | ||||||
|  |  */ | ||||||
|  | static MetaBarrier * | ||||||
|  | barrier_find_nearest(MetaBarrierManager *manager, | ||||||
|  |                      int                 dir, | ||||||
|  |                      int                 x1, | ||||||
|  |                      int                 y1, | ||||||
|  |                      int                 x2, | ||||||
|  |                      int                 y2) | ||||||
|  | { | ||||||
|  |   GList *iter; | ||||||
|  |   MetaBarrier *nearest = NULL; | ||||||
|  |   double min_distance = INT_MAX;      /* can't get higher than that in X anyway */ | ||||||
|  |  | ||||||
|  |   for (iter = manager->barriers; iter; iter = iter->next) | ||||||
|  |     { | ||||||
|  |       MetaBarrier *b = iter->data; | ||||||
|  |       double distance; | ||||||
|  |  | ||||||
|  |       if (b->priv->seen || !b->priv->active) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       if (!barrier_is_blocking_direction (b, dir)) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       if (barrier_is_blocking (b, x1, y1, x2, y2, &distance)) | ||||||
|  |         { | ||||||
|  |           if (min_distance > distance) | ||||||
|  |             { | ||||||
|  |               min_distance = distance; | ||||||
|  |               nearest = b; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   return nearest; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Clamp to the given barrier given the movement direction specified in dir. | ||||||
|  |  * | ||||||
|  |  * @param barrier The barrier to clamp to | ||||||
|  |  * @param dir The movement direction | ||||||
|  |  * @param[out] x The clamped x coordinate. | ||||||
|  |  * @param[out] y The clamped x coordinate. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | barrier_clamp_to_barrier(MetaBarrier *barrier, | ||||||
|  |                          int          dir, | ||||||
|  |                          float       *x, | ||||||
|  |                          float       *y) | ||||||
|  | { | ||||||
|  |   if (barrier_is_vertical (barrier)) | ||||||
|  |     { | ||||||
|  |       if ((dir & META_BARRIER_DIRECTION_NEGATIVE_X) & ~barrier->priv->directions) | ||||||
|  |         *x = barrier->priv->x1; | ||||||
|  |       if ((dir & META_BARRIER_DIRECTION_POSITIVE_X) & ~barrier->priv->directions) | ||||||
|  |         *x = barrier->priv->x1 - 1; | ||||||
|  |     } | ||||||
|  |   if (barrier_is_horizontal (barrier)) | ||||||
|  |     { | ||||||
|  |       if ((dir & META_BARRIER_DIRECTION_NEGATIVE_Y) & ~barrier->priv->directions) | ||||||
|  |         *y = barrier->priv->y1; | ||||||
|  |       if ((dir & META_BARRIER_DIRECTION_POSITIVE_Y) & ~barrier->priv->directions) | ||||||
|  |         *y = barrier->priv->y1 - 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | emit_hit_event (gpointer data) | ||||||
|  | { | ||||||
|  |   MetaBarrierEvent *event = data; | ||||||
|  |  | ||||||
|  |   g_signal_emit (event->barrier, obj_signals[HIT], 0, event); | ||||||
|  |  | ||||||
|  |   meta_barrier_event_unref (event); | ||||||
|  |   return FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | emit_left_event (gpointer data) | ||||||
|  | { | ||||||
|  |   MetaBarrierEvent *event = data; | ||||||
|  |  | ||||||
|  |   g_signal_emit (event->barrier, obj_signals[LEFT], 0, event); | ||||||
|  |  | ||||||
|  |   meta_barrier_event_unref (event); | ||||||
|  |   return FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | meta_barrier_manager_constrain_cursor (MetaBarrierManager *manager, | ||||||
|  |                                        guint32             time, | ||||||
|  |                                        float               current_x, | ||||||
|  |                                        float               current_y, | ||||||
|  |                                        float              *new_x, | ||||||
|  |                                        float              *new_y) | ||||||
|  | { | ||||||
|  |   float x = *new_x; | ||||||
|  |   float y = *new_y; | ||||||
|  |   int dir; | ||||||
|  |   MetaBarrier *nearest = NULL; | ||||||
|  |   GList *iter; | ||||||
|  |   float dx = x - current_x; | ||||||
|  |   float dy = y - current_y; | ||||||
|  |  | ||||||
|  |   /* How this works: | ||||||
|  |    * Given the origin and the movement vector, get the nearest barrier | ||||||
|  |    * to the origin that is blocking the movement. | ||||||
|  |    * Clamp to that barrier. | ||||||
|  |    * Then, check from the clamped intersection to the original | ||||||
|  |    * destination, again finding the nearest barrier and clamping. | ||||||
|  |    */ | ||||||
|  |   dir = barrier_get_direction (current_x, current_y, x, y); | ||||||
|  |  | ||||||
|  |   while (dir != 0) | ||||||
|  |     { | ||||||
|  |       MetaBarrierEvent *event; | ||||||
|  |       gboolean new_sequence; | ||||||
|  |  | ||||||
|  |       nearest = barrier_find_nearest (manager, dir, current_x, current_y, x, y); | ||||||
|  |       if (!nearest) | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |       new_sequence = !nearest->priv->hit; | ||||||
|  |  | ||||||
|  |       nearest->priv->seen = TRUE; | ||||||
|  |       nearest->priv->hit = TRUE; | ||||||
|  |  | ||||||
|  |       if (nearest->priv->barrier_event_id == nearest->priv->release_event_id) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       barrier_clamp_to_barrier (nearest, dir, &x, &y); | ||||||
|  |  | ||||||
|  |       if (barrier_is_vertical (nearest)) | ||||||
|  |         { | ||||||
|  |           dir &= ~(META_BARRIER_DIRECTION_NEGATIVE_X | META_BARRIER_DIRECTION_POSITIVE_X); | ||||||
|  |           current_x = x; | ||||||
|  |         } | ||||||
|  |       else if (barrier_is_horizontal (nearest)) | ||||||
|  |         { | ||||||
|  |           dir &= ~(META_BARRIER_DIRECTION_NEGATIVE_Y | META_BARRIER_DIRECTION_POSITIVE_Y); | ||||||
|  |           current_y = y; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       event = g_slice_new0 (MetaBarrierEvent); | ||||||
|  |  | ||||||
|  |       event->ref_count = 1; | ||||||
|  |       event->barrier = g_object_ref (nearest); | ||||||
|  |       event->event_id = nearest->priv->barrier_event_id; | ||||||
|  |       event->time = time; | ||||||
|  |       event->dt = new_sequence ? 0 : time - nearest->priv->last_timestamp; | ||||||
|  |       event->x = current_x; | ||||||
|  |       event->y = current_y; | ||||||
|  |       event->dx = dx; | ||||||
|  |       event->dy = dy; | ||||||
|  |       event->released = FALSE; | ||||||
|  |       event->grabbed = FALSE; | ||||||
|  |  | ||||||
|  |       g_idle_add (emit_hit_event, event); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   for (iter = manager->barriers; iter; iter = iter->next) | ||||||
|  |     { | ||||||
|  |       MetaBarrierEvent *event; | ||||||
|  |       MetaBarrier *barrier = iter->data; | ||||||
|  |  | ||||||
|  |       if (!barrier->priv->active) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       barrier->priv->seen = FALSE; | ||||||
|  |       if (!barrier->priv->hit) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       if (barrier_inside_hit_box (barrier, x, y)) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       barrier->priv->hit = FALSE; | ||||||
|  |  | ||||||
|  |       event = g_slice_new0 (MetaBarrierEvent); | ||||||
|  |  | ||||||
|  |       event->ref_count = 1; | ||||||
|  |       event->barrier = g_object_ref (barrier); | ||||||
|  |       event->event_id = barrier->priv->barrier_event_id; | ||||||
|  |       event->time = time; | ||||||
|  |       event->dt = time - barrier->priv->last_timestamp; | ||||||
|  |       event->x = current_x; | ||||||
|  |       event->y = current_y; | ||||||
|  |       event->dx = dx; | ||||||
|  |       event->dy = dy; | ||||||
|  |       event->released = barrier->priv->barrier_event_id == barrier->priv->release_event_id; | ||||||
|  |       event->grabbed = FALSE; | ||||||
|  |  | ||||||
|  |       g_idle_add (emit_left_event, event); | ||||||
|  |  | ||||||
|  |       /* If we've left the hit box, this is the | ||||||
|  |        * start of a new event ID. */ | ||||||
|  |       barrier->priv->barrier_event_id++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   *new_x = x; | ||||||
|  |   *new_y = y; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MetaBarrierManager * | ||||||
|  | meta_barrier_manager_get (void) | ||||||
|  | { | ||||||
|  |   if (!global_barrier_manager) | ||||||
|  |     global_barrier_manager = g_new0 (MetaBarrierManager, 1); | ||||||
|  |  | ||||||
|  |   return global_barrier_manager; | ||||||
|  | } | ||||||
|  |  | ||||||
| static MetaBarrierEvent * | static MetaBarrierEvent * | ||||||
| meta_barrier_event_ref (MetaBarrierEvent *event) | meta_barrier_event_ref (MetaBarrierEvent *event) | ||||||
| { | { | ||||||
| @@ -399,7 +872,12 @@ meta_barrier_event_unref (MetaBarrierEvent *event) | |||||||
|   g_return_if_fail (event->ref_count > 0); |   g_return_if_fail (event->ref_count > 0); | ||||||
|  |  | ||||||
|   if (g_atomic_int_dec_and_test ((volatile int *)&event->ref_count)) |   if (g_atomic_int_dec_and_test ((volatile int *)&event->ref_count)) | ||||||
|     g_slice_free (MetaBarrierEvent, event); |     { | ||||||
|  |       if (event->barrier) | ||||||
|  |         g_object_unref (event->barrier); | ||||||
|  |  | ||||||
|  |       g_slice_free (MetaBarrierEvent, event); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| G_DEFINE_BOXED_TYPE (MetaBarrierEvent, | G_DEFINE_BOXED_TYPE (MetaBarrierEvent, | ||||||
|   | |||||||
| @@ -1516,19 +1516,26 @@ meta_display_get_current_time_roundtrip (MetaDisplay *display) | |||||||
| { | { | ||||||
|   guint32 timestamp; |   guint32 timestamp; | ||||||
|  |  | ||||||
|   timestamp = meta_display_get_current_time (display); |   if (meta_is_wayland_compositor ()) | ||||||
|   if (timestamp == CurrentTime) |  | ||||||
|     { |     { | ||||||
|       XEvent property_event; |       timestamp = g_get_monotonic_time () / 1000; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       timestamp = meta_display_get_current_time (display); | ||||||
|  |       if (timestamp == CurrentTime) | ||||||
|  |         { | ||||||
|  |           XEvent property_event; | ||||||
|  |  | ||||||
|       XChangeProperty (display->xdisplay, display->timestamp_pinging_window, |           XChangeProperty (display->xdisplay, display->timestamp_pinging_window, | ||||||
|                        display->atom__MUTTER_TIMESTAMP_PING, |                            display->atom__MUTTER_TIMESTAMP_PING, | ||||||
|                        XA_STRING, 8, PropModeAppend, NULL, 0); |                            XA_STRING, 8, PropModeAppend, NULL, 0); | ||||||
|       XIfEvent (display->xdisplay, |           XIfEvent (display->xdisplay, | ||||||
|                 &property_event, |                     &property_event, | ||||||
|                 find_timestamp_predicate, |                     find_timestamp_predicate, | ||||||
|                 (XPointer) display); |                     (XPointer) display); | ||||||
|       timestamp = property_event.xproperty.time; |           timestamp = property_event.xproperty.time; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   sanity_check_timestamps (display, timestamp); |   sanity_check_timestamps (display, timestamp); | ||||||
| @@ -2190,6 +2197,40 @@ handle_window_focus_event (MetaDisplay  *display, | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | reload_xkb_rules (MetaScreen  *screen) | ||||||
|  | { | ||||||
|  |   MetaWaylandCompositor *compositor; | ||||||
|  |   char **names; | ||||||
|  |   int n_names; | ||||||
|  |   gboolean ok; | ||||||
|  |   const char *rules, *model, *layout, *variant, *options; | ||||||
|  |  | ||||||
|  |   compositor = meta_wayland_compositor_get_default (); | ||||||
|  |  | ||||||
|  |   ok = meta_prop_get_latin1_list (screen->display, screen->xroot, | ||||||
|  |                                   screen->display->atom__XKB_RULES_NAMES, | ||||||
|  |                                   &names, &n_names); | ||||||
|  |   if (!ok) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   if (n_names != 5) | ||||||
|  |     goto out; | ||||||
|  |  | ||||||
|  |   rules = names[0]; | ||||||
|  |   model = names[1]; | ||||||
|  |   layout = names[2]; | ||||||
|  |   variant = names[3]; | ||||||
|  |   options = names[4]; | ||||||
|  |  | ||||||
|  |   meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard, | ||||||
|  |                                           rules, model, layout, variant, options, | ||||||
|  |                                           META_WAYLAND_KEYBOARD_SKIP_XCLIENTS); | ||||||
|  |  | ||||||
|  |  out: | ||||||
|  |   g_strfreev (names); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * meta_display_handle_event: |  * meta_display_handle_event: | ||||||
|  * @display: The MetaDisplay that events are coming from |  * @display: The MetaDisplay that events are coming from | ||||||
| @@ -2962,6 +3003,10 @@ meta_display_handle_event (MetaDisplay *display, | |||||||
|                 else if (event->xproperty.atom == |                 else if (event->xproperty.atom == | ||||||
|                          display->atom__NET_DESKTOP_NAMES) |                          display->atom__NET_DESKTOP_NAMES) | ||||||
|                   meta_screen_update_workspace_names (screen); |                   meta_screen_update_workspace_names (screen); | ||||||
|  |                 else if (meta_is_wayland_compositor () && | ||||||
|  |                          event->xproperty.atom == | ||||||
|  |                          display->atom__XKB_RULES_NAMES) | ||||||
|  |                   reload_xkb_rules (screen); | ||||||
| #if 0 | #if 0 | ||||||
|                 else if (event->xproperty.atom == |                 else if (event->xproperty.atom == | ||||||
|                          display->atom__NET_RESTACK_WINDOW) |                          display->atom__NET_RESTACK_WINDOW) | ||||||
| @@ -3197,7 +3242,9 @@ event_callback (XEvent  *event, | |||||||
|      translation altogether by directly using the Clutter events */ |      translation altogether by directly using the Clutter events */ | ||||||
|   if (meta_is_wayland_compositor () && |   if (meta_is_wayland_compositor () && | ||||||
|       event->type == GenericEvent && |       event->type == GenericEvent && | ||||||
|       event->xcookie.evtype == XI_Motion) |       (event->xcookie.evtype == XI_Motion || | ||||||
|  |        event->xcookie.evtype == XI_KeyPress || | ||||||
|  |        event->xcookie.evtype == XI_KeyRelease)) | ||||||
|     return FALSE; |     return FALSE; | ||||||
|  |  | ||||||
|   return meta_display_handle_event (display, event); |   return meta_display_handle_event (display, event); | ||||||
| @@ -6031,7 +6078,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display) | |||||||
| gboolean | gboolean | ||||||
| meta_display_supports_extended_barriers (MetaDisplay *display) | meta_display_supports_extended_barriers (MetaDisplay *display) | ||||||
| { | { | ||||||
|   return META_DISPLAY_HAS_XINPUT_23 (display) && !meta_is_wayland_compositor (); |   return meta_is_wayland_compositor () || META_DISPLAY_HAS_XINPUT_23 (display); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -2065,22 +2065,22 @@ meta_display_process_key_event (MetaDisplay   *display, | |||||||
|   gboolean handled; |   gboolean handled; | ||||||
|   const char *str; |   const char *str; | ||||||
|   MetaScreen *screen; |   MetaScreen *screen; | ||||||
|  |   gboolean was_current_time; | ||||||
|  |  | ||||||
|   /* if key event was on root window, we have a shortcut */ |   /* We only ever have one screen */ | ||||||
|   screen = meta_display_screen_for_root (display, event->event); |   screen = display->screens->data; | ||||||
|  |  | ||||||
|   /* else round-trip to server */ |  | ||||||
|   if (screen == NULL) |  | ||||||
|     screen = meta_display_screen_for_xwindow (display, event->event); |  | ||||||
|  |  | ||||||
|   if (screen == NULL) |  | ||||||
|     return FALSE; /* event window is destroyed */ |  | ||||||
|  |  | ||||||
|   /* ignore key events on popup menus and such. */ |   /* ignore key events on popup menus and such. */ | ||||||
|   if (meta_ui_window_is_widget (screen->ui, event->event)) |   if (meta_ui_window_is_widget (screen->ui, event->event)) | ||||||
|     return FALSE; |     return FALSE; | ||||||
|  |  | ||||||
|   /* window may be NULL */ |   if (display->current_time == CurrentTime) | ||||||
|  |     { | ||||||
|  |       display->current_time = event->time; | ||||||
|  |       was_current_time = TRUE; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     was_current_time = FALSE; | ||||||
|  |  | ||||||
|   keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0); |   keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0); | ||||||
|  |  | ||||||
| @@ -2098,11 +2098,11 @@ meta_display_process_key_event (MetaDisplay   *display, | |||||||
|     { |     { | ||||||
|       handled = process_overlay_key (display, screen, event, keysym); |       handled = process_overlay_key (display, screen, event, keysym); | ||||||
|       if (handled) |       if (handled) | ||||||
|         return TRUE; |         goto out; | ||||||
|  |  | ||||||
|       handled = process_iso_next_group (display, screen, event, keysym); |       handled = process_iso_next_group (display, screen, event, keysym); | ||||||
|       if (handled) |       if (handled) | ||||||
|         return TRUE; |         goto out; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   XIAllowEvents (display->xdisplay, event->deviceid, |   XIAllowEvents (display->xdisplay, event->deviceid, | ||||||
| @@ -2112,7 +2112,11 @@ meta_display_process_key_event (MetaDisplay   *display, | |||||||
|   if (all_keys_grabbed) |   if (all_keys_grabbed) | ||||||
|     { |     { | ||||||
|       if (display->grab_op == META_GRAB_OP_NONE) |       if (display->grab_op == META_GRAB_OP_NONE) | ||||||
|         return TRUE; |         { | ||||||
|  |           handled = TRUE; | ||||||
|  |           goto out; | ||||||
|  |         } | ||||||
|  |  | ||||||
|       /* If we get here we have a global grab, because |       /* If we get here we have a global grab, because | ||||||
|        * we're in some special keyboard mode such as window move |        * we're in some special keyboard mode such as window move | ||||||
|        * mode. |        * mode. | ||||||
| @@ -2191,14 +2195,20 @@ meta_display_process_key_event (MetaDisplay   *display, | |||||||
|           meta_display_end_grab_op (display, event->time); |           meta_display_end_grab_op (display, event->time); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|       return TRUE; |       handled = TRUE; | ||||||
|  |       goto out; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   /* Do the normal keybindings */ |   /* Do the normal keybindings */ | ||||||
|   return process_event (display->key_bindings, |   handled = process_event (display->key_bindings, | ||||||
|                         display->n_key_bindings, |                            display->n_key_bindings, | ||||||
|                         display, screen, window, event, keysym, |                            display, screen, window, event, keysym, | ||||||
|                         !all_keys_grabbed && window); |                            !all_keys_grabbed && window); | ||||||
|  |  | ||||||
|  |  out: | ||||||
|  |   if (was_current_time) | ||||||
|  |     display->current_time = CurrentTime; | ||||||
|  |   return handled; | ||||||
| } | } | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
|   | |||||||
| @@ -401,6 +401,9 @@ meta_init (void) | |||||||
|                 g_strerror (errno)); |                 g_strerror (errno)); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |   if (getenv ("MUTTER_SLEEP_INIT")) | ||||||
|  |     sleep (60); | ||||||
|  |  | ||||||
|   g_unix_signal_add (SIGTERM, on_sigterm, NULL); |   g_unix_signal_add (SIGTERM, on_sigterm, NULL); | ||||||
|  |  | ||||||
|   if (g_getenv ("MUTTER_VERBOSE")) |   if (g_getenv ("MUTTER_VERBOSE")) | ||||||
|   | |||||||
| @@ -536,6 +536,81 @@ meta_prop_get_utf8_list (MetaDisplay   *display, | |||||||
|   return utf8_list_from_results (&results, str_p, n_str_p); |   return utf8_list_from_results (&results, str_p, n_str_p); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* this one freakishly returns g_malloc memory */ | ||||||
|  | static gboolean | ||||||
|  | latin1_list_from_results (GetPropertyResults *results, | ||||||
|  |                         char             ***str_p, | ||||||
|  |                         int                *n_str_p) | ||||||
|  | { | ||||||
|  |   int i; | ||||||
|  |   int n_strings; | ||||||
|  |   char **retval; | ||||||
|  |   const char *p; | ||||||
|  |    | ||||||
|  |   *str_p = NULL; | ||||||
|  |   *n_str_p = 0; | ||||||
|  |  | ||||||
|  |   if (!validate_or_free_results (results, 8, XA_STRING, FALSE)) | ||||||
|  |     return FALSE; | ||||||
|  |    | ||||||
|  |   /* I'm not sure this is right, but I'm guessing the | ||||||
|  |    * property is nul-separated | ||||||
|  |    */ | ||||||
|  |   i = 0; | ||||||
|  |   n_strings = 0; | ||||||
|  |   while (i < (int) results->n_items) | ||||||
|  |     { | ||||||
|  |       if (results->prop[i] == '\0') | ||||||
|  |         ++n_strings; | ||||||
|  |       ++i; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   if (results->prop[results->n_items - 1] != '\0') | ||||||
|  |     ++n_strings; | ||||||
|  |   | ||||||
|  |   /* we're guaranteed that results->prop has a nul on the end | ||||||
|  |    * by XGetWindowProperty | ||||||
|  |    */ | ||||||
|  |    | ||||||
|  |   retval = g_new0 (char*, n_strings + 1); | ||||||
|  |  | ||||||
|  |   p = (char *)results->prop; | ||||||
|  |   i = 0; | ||||||
|  |   while (i < n_strings) | ||||||
|  |     { | ||||||
|  |       retval[i] = g_strdup (p); | ||||||
|  |        | ||||||
|  |       p = p + strlen (p) + 1; | ||||||
|  |       ++i; | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |   *str_p = retval; | ||||||
|  |   *n_str_p = i; | ||||||
|  |  | ||||||
|  |   meta_XFree (results->prop); | ||||||
|  |   results->prop = NULL; | ||||||
|  |  | ||||||
|  |   return TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | gboolean | ||||||
|  | meta_prop_get_latin1_list (MetaDisplay   *display, | ||||||
|  |                            Window         xwindow, | ||||||
|  |                            Atom           xatom, | ||||||
|  |                            char        ***str_p, | ||||||
|  |                            int           *n_str_p) | ||||||
|  | { | ||||||
|  |   GetPropertyResults results; | ||||||
|  |  | ||||||
|  |   *str_p = NULL; | ||||||
|  |  | ||||||
|  |   if (!get_property (display, xwindow, xatom, | ||||||
|  |                      XA_STRING, &results)) | ||||||
|  |     return FALSE; | ||||||
|  |  | ||||||
|  |   return latin1_list_from_results (&results, str_p, n_str_p); | ||||||
|  | } | ||||||
|  |  | ||||||
| void | void | ||||||
| meta_prop_set_utf8_string_hint (MetaDisplay *display, | meta_prop_set_utf8_string_hint (MetaDisplay *display, | ||||||
|                                 Window xwindow, |                                 Window xwindow, | ||||||
|   | |||||||
| @@ -102,6 +102,11 @@ gboolean meta_prop_get_utf8_list     (MetaDisplay   *display, | |||||||
|                                       Atom           xatom, |                                       Atom           xatom, | ||||||
|                                       char        ***str_p, |                                       char        ***str_p, | ||||||
|                                       int           *n_str_p); |                                       int           *n_str_p); | ||||||
|  | gboolean meta_prop_get_latin1_list   (MetaDisplay   *display, | ||||||
|  |                                       Window         xwindow, | ||||||
|  |                                       Atom           xatom, | ||||||
|  |                                       char        ***str_p, | ||||||
|  |                                       int           *n_str_p); | ||||||
| void     meta_prop_set_utf8_string_hint | void     meta_prop_set_utf8_string_hint | ||||||
|                                      (MetaDisplay *display, |                                      (MetaDisplay *display, | ||||||
|                                       Window xwindow, |                                       Window xwindow, | ||||||
|   | |||||||
| @@ -81,6 +81,7 @@ item(TIMESTAMP) | |||||||
| item(VERSION) | item(VERSION) | ||||||
| item(ATOM_PAIR) | item(ATOM_PAIR) | ||||||
| item(BACKLIGHT) | item(BACKLIGHT) | ||||||
|  | item(_XKB_RULES_NAMES) | ||||||
|  |  | ||||||
| /* Oddities: These are used, and we need atoms for them, | /* Oddities: These are used, and we need atoms for them, | ||||||
|  * but when we need all _NET_WM hints (i.e. when we're making |  * but when we need all _NET_WM hints (i.e. when we're making | ||||||
|   | |||||||
| @@ -94,6 +94,7 @@ typedef enum { | |||||||
| struct _MetaBarrierEvent { | struct _MetaBarrierEvent { | ||||||
|   /* < private > */ |   /* < private > */ | ||||||
|   volatile guint ref_count; |   volatile guint ref_count; | ||||||
|  |   MetaBarrier *barrier; | ||||||
|  |  | ||||||
|   /* < public > */ |   /* < public > */ | ||||||
|   int event_id; |   int event_id; | ||||||
|   | |||||||
| @@ -106,11 +106,49 @@ create_anonymous_file (off_t size, | |||||||
|   return -1; |   return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| static gboolean | static void | ||||||
| meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info) | inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard, | ||||||
|  | 			      int                  flags) | ||||||
| { | { | ||||||
|  |   MetaWaylandCompositor *compositor; | ||||||
|  |   struct wl_client *xclient; | ||||||
|  |   struct wl_resource *keyboard_resource; | ||||||
|  |  | ||||||
|  |   compositor = meta_wayland_compositor_get_default (); | ||||||
|  |   xclient = compositor->xwayland_client; | ||||||
|  |  | ||||||
|  |   wl_resource_for_each (keyboard_resource, &keyboard->resource_list) | ||||||
|  |     { | ||||||
|  |       if ((flags & META_WAYLAND_KEYBOARD_SKIP_XCLIENTS) && | ||||||
|  | 	  wl_resource_get_client (keyboard_resource) == xclient) | ||||||
|  | 	continue; | ||||||
|  |  | ||||||
|  |       wl_keyboard_send_keymap (keyboard_resource, | ||||||
|  | 			       WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, | ||||||
|  | 			       keyboard->xkb_info.keymap_fd, | ||||||
|  | 			       keyboard->xkb_info.keymap_size); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard, | ||||||
|  | 				   struct xkb_keymap   *keymap, | ||||||
|  | 				   int                  flags) | ||||||
|  | { | ||||||
|  |   MetaWaylandXkbInfo  *xkb_info = &keyboard->xkb_info; | ||||||
|   GError *error = NULL; |   GError *error = NULL; | ||||||
|   char *keymap_str; |   char *keymap_str; | ||||||
|  |   size_t previous_size; | ||||||
|  |  | ||||||
|  |   if (keymap == NULL) | ||||||
|  |     { | ||||||
|  |       g_warning ("Attempting to set null keymap (compilation probably failed)"); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   if (xkb_info->keymap) | ||||||
|  |     xkb_keymap_unref (xkb_info->keymap); | ||||||
|  |   xkb_info->keymap = keymap; | ||||||
|  |  | ||||||
|   xkb_info->shift_mod = |   xkb_info->shift_mod = | ||||||
|     xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT); |     xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT); | ||||||
| @@ -129,21 +167,28 @@ meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info) | |||||||
|   keymap_str = xkb_map_get_as_string (xkb_info->keymap); |   keymap_str = xkb_map_get_as_string (xkb_info->keymap); | ||||||
|   if (keymap_str == NULL) |   if (keymap_str == NULL) | ||||||
|     { |     { | ||||||
|       g_warning ("failed to get string version of keymap\n"); |       g_warning ("failed to get string version of keymap"); | ||||||
|       return FALSE; |       return; | ||||||
|     } |     } | ||||||
|  |   previous_size = xkb_info->keymap_size; | ||||||
|   xkb_info->keymap_size = strlen (keymap_str) + 1; |   xkb_info->keymap_size = strlen (keymap_str) + 1; | ||||||
|  |  | ||||||
|  |   if (xkb_info->keymap_fd >= 0) | ||||||
|  |     close (xkb_info->keymap_fd); | ||||||
|  |  | ||||||
|   xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error); |   xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error); | ||||||
|   if (xkb_info->keymap_fd < 0) |   if (xkb_info->keymap_fd < 0) | ||||||
|     { |     { | ||||||
|       g_warning ("creating a keymap file for %lu bytes failed: %s\n", |       g_warning ("creating a keymap file for %lu bytes failed: %s", | ||||||
|                  (unsigned long) xkb_info->keymap_size, |                  (unsigned long) xkb_info->keymap_size, | ||||||
|                  error->message); |                  error->message); | ||||||
|       g_clear_error (&error); |       g_clear_error (&error); | ||||||
|       goto err_keymap_str; |       goto err_keymap_str; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |   if (xkb_info->keymap_area) | ||||||
|  |     munmap (xkb_info->keymap_area, previous_size); | ||||||
|  |  | ||||||
|   xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size, |   xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size, | ||||||
|                                 PROT_READ | PROT_WRITE, |                                 PROT_READ | PROT_WRITE, | ||||||
|                                 MAP_SHARED, xkb_info->keymap_fd, 0); |                                 MAP_SHARED, xkb_info->keymap_fd, 0); | ||||||
| @@ -156,41 +201,24 @@ meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info) | |||||||
|   strcpy (xkb_info->keymap_area, keymap_str); |   strcpy (xkb_info->keymap_area, keymap_str); | ||||||
|   free (keymap_str); |   free (keymap_str); | ||||||
|  |  | ||||||
|   return TRUE; |   if (keyboard->is_evdev) | ||||||
|  |     { | ||||||
|  |       ClutterDeviceManager *manager; | ||||||
|  |  | ||||||
|  |       manager = clutter_device_manager_get_default (); | ||||||
|  |       clutter_evdev_set_keyboard_map (manager, xkb_info->keymap); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   inform_clients_of_new_keymap (keyboard, flags); | ||||||
|  |  | ||||||
|  |   return; | ||||||
|  |  | ||||||
| err_dev_zero: | err_dev_zero: | ||||||
|   close (xkb_info->keymap_fd); |   close (xkb_info->keymap_fd); | ||||||
|   xkb_info->keymap_fd = -1; |   xkb_info->keymap_fd = -1; | ||||||
| err_keymap_str: | err_keymap_str: | ||||||
|   free (keymap_str); |   free (keymap_str); | ||||||
|   return FALSE; |   return; | ||||||
| } |  | ||||||
|  |  | ||||||
| static gboolean |  | ||||||
| meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context, |  | ||||||
|                                            struct xkb_rule_names *xkb_names, |  | ||||||
|                                            MetaWaylandXkbInfo *xkb_info) |  | ||||||
| { |  | ||||||
|   xkb_info->keymap = xkb_map_new_from_names (xkb_context, |  | ||||||
|                                              xkb_names, |  | ||||||
|                                              0 /* flags */); |  | ||||||
|   if (xkb_info->keymap == NULL) |  | ||||||
|     { |  | ||||||
|       g_warning ("failed to compile global XKB keymap\n" |  | ||||||
|                  "  tried rules %s, model %s, layout %s, variant %s, " |  | ||||||
|                  "options %s\n", |  | ||||||
|                  xkb_names->rules, |  | ||||||
|                  xkb_names->model, |  | ||||||
|                  xkb_names->layout, |  | ||||||
|                  xkb_names->variant, |  | ||||||
|                  xkb_names->options); |  | ||||||
|       return FALSE; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   if (!meta_wayland_xkb_info_new_keymap (xkb_info)) |  | ||||||
|     return FALSE; |  | ||||||
|  |  | ||||||
|   return TRUE; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| @@ -306,9 +334,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, | |||||||
|                             struct wl_display   *display, |                             struct wl_display   *display, | ||||||
| 			    gboolean             is_evdev) | 			    gboolean             is_evdev) | ||||||
| { | { | ||||||
|   ClutterDeviceManager *manager; |  | ||||||
|  |  | ||||||
|   memset (keyboard, 0, sizeof *keyboard); |   memset (keyboard, 0, sizeof *keyboard); | ||||||
|  |   keyboard->xkb_info.keymap_fd = -1; | ||||||
|  |  | ||||||
|   wl_list_init (&keyboard->resource_list); |   wl_list_init (&keyboard->resource_list); | ||||||
|   wl_array_init (&keyboard->keys); |   wl_array_init (&keyboard->keys); | ||||||
| @@ -320,18 +347,15 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, | |||||||
|   keyboard->display = display; |   keyboard->display = display; | ||||||
|  |  | ||||||
|   keyboard->xkb_context = xkb_context_new (0 /* flags */); |   keyboard->xkb_context = xkb_context_new (0 /* flags */); | ||||||
|  |  | ||||||
|   meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context, |  | ||||||
| 					     &keyboard->xkb_names, |  | ||||||
| 					     &keyboard->xkb_info); |  | ||||||
|  |  | ||||||
|   keyboard->is_evdev = is_evdev; |   keyboard->is_evdev = is_evdev; | ||||||
|   if (is_evdev) |  | ||||||
|     { |  | ||||||
|       manager = clutter_device_manager_get_default (); |  | ||||||
|  |  | ||||||
|       clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap); |   /* Compute a default until gnome-settings-daemon starts and sets | ||||||
|     } |      the appropriate values | ||||||
|  |   */ | ||||||
|  |   meta_wayland_keyboard_set_keymap_names (keyboard, | ||||||
|  | 					  "evdev", | ||||||
|  | 					  "pc105", | ||||||
|  | 					  "us", "", "", 0); | ||||||
|  |  | ||||||
|   return TRUE; |   return TRUE; | ||||||
| } | } | ||||||
| @@ -388,6 +412,81 @@ set_modifiers (MetaWaylandKeyboard *keyboard, | |||||||
|                               new_state.group); |                               new_state.group); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #define N_BUTTONS 5 | ||||||
|  |  | ||||||
|  | static gboolean | ||||||
|  | process_keybinding (MetaWaylandKeyboard   *keyboard, | ||||||
|  | 		    const ClutterEvent    *event) | ||||||
|  | { | ||||||
|  |   MetaWaylandSurface *surface; | ||||||
|  |   XGenericEventCookie generic_event; | ||||||
|  |   XIDeviceEvent device_event; | ||||||
|  |   unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 }; | ||||||
|  |   MetaDisplay *display = meta_get_display (); | ||||||
|  |   ClutterModifierType button_state; | ||||||
|  |   int i; | ||||||
|  |  | ||||||
|  |   if (!display) /* not initialized yet */ | ||||||
|  |     return FALSE; | ||||||
|  |  | ||||||
|  |   generic_event.type = GenericEvent; | ||||||
|  |   generic_event.serial = 0; | ||||||
|  |   generic_event.send_event = False; | ||||||
|  |   generic_event.display = display->xdisplay; | ||||||
|  |   generic_event.extension = display->xinput_opcode; | ||||||
|  |   if (clutter_event_type (event) == CLUTTER_KEY_PRESS) | ||||||
|  |     generic_event.evtype = XI_KeyPress; | ||||||
|  |   else | ||||||
|  |     generic_event.evtype = XI_KeyRelease; | ||||||
|  |   /* Mutter assumes the data for the event is already retrieved by GDK | ||||||
|  |    * so we don't need the cookie */ | ||||||
|  |   generic_event.cookie = 0; | ||||||
|  |   generic_event.data = &device_event; | ||||||
|  |  | ||||||
|  |   memcpy (&device_event, &generic_event, sizeof (XGenericEvent)); | ||||||
|  |  | ||||||
|  |   device_event.time = clutter_event_get_time (event); | ||||||
|  |   device_event.deviceid = clutter_event_get_device_id (event); | ||||||
|  |   device_event.sourceid = 0; /* not used, not sure what this should be */ | ||||||
|  |   device_event.detail = clutter_event_get_key_code (event); | ||||||
|  |   device_event.root = DefaultRootWindow (display->xdisplay); | ||||||
|  |   device_event.flags = 0; | ||||||
|  |  | ||||||
|  |   surface = keyboard->focus; | ||||||
|  |   if (surface) | ||||||
|  |     device_event.event = surface->window ? surface->window->xwindow : device_event.root; | ||||||
|  |   else | ||||||
|  |     device_event.event = device_event.root; | ||||||
|  |  | ||||||
|  |   /* Mutter doesn't really know about the sub-windows. This assumes it | ||||||
|  |      doesn't care either */ | ||||||
|  |   device_event.child = device_event.event; | ||||||
|  |   device_event.root_x = 0; | ||||||
|  |   device_event.root_y = 0; | ||||||
|  |  | ||||||
|  |   clutter_event_get_state_full (event, | ||||||
|  | 				&button_state, | ||||||
|  | 				(ClutterModifierType*)&device_event.mods.base, | ||||||
|  | 				(ClutterModifierType*)&device_event.mods.latched, | ||||||
|  | 				(ClutterModifierType*)&device_event.mods.locked, | ||||||
|  | 				(ClutterModifierType*)&device_event.mods.effective); | ||||||
|  |   device_event.mods.effective &= ~button_state; | ||||||
|  |   memset (&device_event.group, 0, sizeof (device_event.group)); | ||||||
|  |   device_event.group.effective = (device_event.mods.effective >> 13) & 0x3; | ||||||
|  |  | ||||||
|  |   for (i = 0; i < N_BUTTONS; i++) | ||||||
|  |     if ((button_state & (CLUTTER_BUTTON1_MASK << i))) | ||||||
|  |       XISetMask (button_mask, i + 1); | ||||||
|  |   device_event.buttons.mask_len = N_BUTTONS + 1; | ||||||
|  |   device_event.buttons.mask = button_mask; | ||||||
|  |  | ||||||
|  |   device_event.valuators.mask_len = 0; | ||||||
|  |   device_event.valuators.mask = NULL; | ||||||
|  |   device_event.valuators.values = NULL; | ||||||
|  |  | ||||||
|  |   return meta_display_process_key_event (display, surface ? surface->window : NULL, &device_event); | ||||||
|  | } | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| update_pressed_keys (MetaWaylandKeyboard   *keyboard, | update_pressed_keys (MetaWaylandKeyboard   *keyboard, | ||||||
| 		     uint32_t               evdev_code, | 		     uint32_t               evdev_code, | ||||||
| @@ -460,6 +559,10 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, | |||||||
| 		autorepeat ? " (autorepeat)" : "", | 		autorepeat ? " (autorepeat)" : "", | ||||||
| 		xkb_keycode); | 		xkb_keycode); | ||||||
|  |  | ||||||
|  |   /* Give a chance to process keybindings */ | ||||||
|  |   if (process_keybinding (keyboard, (ClutterEvent*) event)) | ||||||
|  |     return TRUE; | ||||||
|  |  | ||||||
|   if (autorepeat) |   if (autorepeat) | ||||||
|     return FALSE; |     return FALSE; | ||||||
|  |  | ||||||
| @@ -559,12 +662,6 @@ meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard) | |||||||
| void | void | ||||||
| meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard) | meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard) | ||||||
| { | { | ||||||
|   g_free ((char *) keyboard->xkb_names.rules); |  | ||||||
|   g_free ((char *) keyboard->xkb_names.model); |  | ||||||
|   g_free ((char *) keyboard->xkb_names.layout); |  | ||||||
|   g_free ((char *) keyboard->xkb_names.variant); |  | ||||||
|   g_free ((char *) keyboard->xkb_names.options); |  | ||||||
|  |  | ||||||
|   meta_wayland_xkb_info_destroy (&keyboard->xkb_info); |   meta_wayland_xkb_info_destroy (&keyboard->xkb_info); | ||||||
|   xkb_context_unref (keyboard->xkb_context); |   xkb_context_unref (keyboard->xkb_context); | ||||||
|  |  | ||||||
| @@ -652,3 +749,28 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard, | |||||||
|  |  | ||||||
|   meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp); |   meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard, | ||||||
|  | 					const char          *rules, | ||||||
|  | 					const char          *model, | ||||||
|  | 					const char          *layout, | ||||||
|  | 					const char          *variant, | ||||||
|  | 					const char          *options, | ||||||
|  | 					int                  flags) | ||||||
|  | { | ||||||
|  |   struct xkb_rule_names xkb_names; | ||||||
|  |  | ||||||
|  |   xkb_names.rules = rules; | ||||||
|  |   xkb_names.model = model; | ||||||
|  |   xkb_names.layout = layout; | ||||||
|  |   xkb_names.variant = variant; | ||||||
|  |   xkb_names.options = options; | ||||||
|  |  | ||||||
|  |   meta_wayland_keyboard_take_keymap (keyboard, | ||||||
|  | 				     xkb_keymap_new_from_names (keyboard->xkb_context, | ||||||
|  | 								&xkb_names, | ||||||
|  | 								0 /* flags */), | ||||||
|  | 				     flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -112,7 +112,6 @@ struct _MetaWaylandKeyboard | |||||||
|   struct xkb_context *xkb_context; |   struct xkb_context *xkb_context; | ||||||
|   gboolean is_evdev; |   gboolean is_evdev; | ||||||
|   MetaWaylandXkbInfo xkb_info; |   MetaWaylandXkbInfo xkb_info; | ||||||
|   struct xkb_rule_names xkb_names; |  | ||||||
|  |  | ||||||
|   MetaWaylandKeyboardGrab input_method_grab; |   MetaWaylandKeyboardGrab input_method_grab; | ||||||
|   struct wl_resource *input_method_resource; |   struct wl_resource *input_method_resource; | ||||||
| @@ -123,6 +122,18 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, | |||||||
|                             struct wl_display   *display, |                             struct wl_display   *display, | ||||||
| 			    gboolean             is_evdev); | 			    gboolean             is_evdev); | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1, | ||||||
|  | } MetaWaylandKeyboardSetKeymapFlags; | ||||||
|  |  | ||||||
|  | void | ||||||
|  | meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard, | ||||||
|  | 					const char          *rules, | ||||||
|  | 					const char          *model, | ||||||
|  | 					const char          *layout, | ||||||
|  | 					const char          *variant, | ||||||
|  | 					const char          *options, | ||||||
|  | 					int                  flags); | ||||||
| gboolean | gboolean | ||||||
| meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, | meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, | ||||||
|                                     const ClutterKeyEvent *event); |                                     const ClutterKeyEvent *event); | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ | |||||||
|  |  | ||||||
| #include "meta-wayland-pointer.h" | #include "meta-wayland-pointer.h" | ||||||
| #include "meta-wayland-private.h" | #include "meta-wayland-private.h" | ||||||
|  | #include "barrier-private.h" | ||||||
|  |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  |  | ||||||
| @@ -165,10 +166,10 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = { | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| static gboolean | static gboolean | ||||||
| check_all_screen_monitors(MetaMonitorInfo *monitors, | check_all_screen_monitors (MetaMonitorInfo *monitors, | ||||||
| 			  unsigned         n_monitors, | 			   unsigned         n_monitors, | ||||||
| 			  float            x, | 			   float            x, | ||||||
| 			  float            y) | 			   float            y) | ||||||
| { | { | ||||||
|   unsigned int i; |   unsigned int i; | ||||||
|  |  | ||||||
| @@ -193,14 +194,13 @@ static void | |||||||
| constrain_all_screen_monitors (ClutterInputDevice *device, | constrain_all_screen_monitors (ClutterInputDevice *device, | ||||||
| 			       MetaMonitorInfo    *monitors, | 			       MetaMonitorInfo    *monitors, | ||||||
| 			       unsigned            n_monitors, | 			       unsigned            n_monitors, | ||||||
|  | 			       float               current_x, | ||||||
|  | 			       float               current_y, | ||||||
| 			       float              *x, | 			       float              *x, | ||||||
| 			       float              *y) | 			       float              *y) | ||||||
| { | { | ||||||
|   ClutterPoint current; |  | ||||||
|   unsigned int i; |   unsigned int i; | ||||||
|  |  | ||||||
|   clutter_input_device_get_coords (device, NULL, ¤t); |  | ||||||
|  |  | ||||||
|   /* if we're trying to escape, clamp to the CRTC we're coming from */ |   /* if we're trying to escape, clamp to the CRTC we're coming from */ | ||||||
|   for (i = 0; i < n_monitors; i++) |   for (i = 0; i < n_monitors; i++) | ||||||
|     { |     { | ||||||
| @@ -213,8 +213,8 @@ constrain_all_screen_monitors (ClutterInputDevice *device, | |||||||
|       top = monitor->rect.y; |       top = monitor->rect.y; | ||||||
|       bottom = left + monitor->rect.height; |       bottom = left + monitor->rect.height; | ||||||
|  |  | ||||||
|       nx = current.x; |       nx = current_x; | ||||||
|       ny = current.y; |       ny = current_y; | ||||||
|  |  | ||||||
|       if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) |       if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) | ||||||
| 	{ | 	{ | ||||||
| @@ -239,21 +239,32 @@ pointer_constrain_callback (ClutterInputDevice *device, | |||||||
| 			    float              *new_y, | 			    float              *new_y, | ||||||
| 			    gpointer            user_data) | 			    gpointer            user_data) | ||||||
| { | { | ||||||
|  |   MetaBarrierManager *barrier_manager; | ||||||
|   MetaMonitorManager *monitor_manager; |   MetaMonitorManager *monitor_manager; | ||||||
|   MetaMonitorInfo *monitors; |   MetaMonitorInfo *monitors; | ||||||
|   unsigned int n_monitors; |   unsigned int n_monitors; | ||||||
|   gboolean ret; |   gboolean ret; | ||||||
|  |   ClutterPoint current; | ||||||
|  |  | ||||||
|  |   clutter_input_device_get_coords (device, NULL, ¤t); | ||||||
|  |  | ||||||
|  |   barrier_manager = meta_barrier_manager_get (); | ||||||
|   monitor_manager = meta_monitor_manager_get (); |   monitor_manager = meta_monitor_manager_get (); | ||||||
|   monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors); |   monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors); | ||||||
|  |  | ||||||
|  |   meta_barrier_manager_constrain_cursor (barrier_manager, time, | ||||||
|  | 					 current.x, current.y, | ||||||
|  | 					 new_x, new_y); | ||||||
|  |  | ||||||
|   /* if we're moving inside a monitor, we're fine */ |   /* if we're moving inside a monitor, we're fine */ | ||||||
|   ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y); |   ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y); | ||||||
|   if (ret == TRUE) |   if (ret) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   /* if we're trying to escape, clamp to the CRTC we're coming from */ |   /* if we're trying to escape, clamp to the CRTC we're coming from */ | ||||||
|   constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y); |   constrain_all_screen_monitors(device, monitors, n_monitors, | ||||||
|  | 				current.x, current.y, | ||||||
|  | 				new_x, new_y); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
|   | |||||||
| @@ -697,12 +697,7 @@ event_cb (ClutterActor *stage, | |||||||
|  |  | ||||||
|       if (surface && surface->window && |       if (surface && surface->window && | ||||||
| 	  surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) | 	  surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) | ||||||
|         { | 	meta_window_focus (surface->window, clutter_event_get_time (event)); | ||||||
| 	  MetaDisplay *display = meta_get_display (); |  | ||||||
| 	  guint32 timestamp = meta_display_get_current_time_roundtrip (display); |  | ||||||
|  |  | ||||||
| 	  meta_window_focus (surface->window, timestamp); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (seat->cursor_tracker) |   if (seat->cursor_tracker) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user