Compare commits
	
		
			6 Commits
		
	
	
		
			3.33.4
			...
			wip/waylan
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 34398b273c | ||
|   | 00a73c5bdc | ||
|   | 20cd02f086 | ||
|   | 0cb9392686 | ||
|   | 57f0b1d46d | ||
|   | e2d8d886a8 | 
| @@ -52,6 +52,7 @@ libmutter_wayland_la_SOURCES =			\ | ||||
| 	core/async-getprop.h			\ | ||||
| 	core/barrier.c				\ | ||||
| 	meta/barrier.h				\ | ||||
| 	core/barrier-private.h			\ | ||||
| 	core/bell.c				\ | ||||
| 	core/bell.h				\ | ||||
| 	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; -*- */ | ||||
|  | ||||
| /*  | ||||
|  * 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 | ||||
|  * @Title: MetaBarrier | ||||
| @@ -9,6 +31,7 @@ | ||||
| #include "config.h" | ||||
|  | ||||
| #include <glib-object.h> | ||||
| #include <math.h> | ||||
|  | ||||
| #include <X11/extensions/XInput2.h> | ||||
| #include <X11/extensions/Xfixes.h> | ||||
| @@ -16,6 +39,7 @@ | ||||
| #include <meta/barrier.h> | ||||
| #include "display-private.h" | ||||
| #include "mutter-enum-types.h" | ||||
| #include "barrier-private.h" | ||||
| #include "core.h" | ||||
|  | ||||
| G_DEFINE_TYPE (MetaBarrier, meta_barrier, G_TYPE_OBJECT) | ||||
| @@ -56,9 +80,23 @@ struct _MetaBarrierPrivate | ||||
|  | ||||
|   MetaBarrierDirection directions; | ||||
|  | ||||
|   /* x11 */ | ||||
|   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 | ||||
| @@ -148,7 +186,10 @@ meta_barrier_dispose (GObject *object) | ||||
| gboolean | ||||
| 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, | ||||
|                       MetaBarrierEvent *event) | ||||
| { | ||||
| #ifdef HAVE_XI23 | ||||
|   MetaBarrierPrivate *priv = barrier->priv; | ||||
|   if (META_DISPLAY_HAS_XINPUT_23 (priv->display)) | ||||
|   MetaBarrierPrivate *priv; | ||||
|  | ||||
|   priv = barrier->priv; | ||||
|  | ||||
|   if (meta_is_wayland_compositor ()) | ||||
|     { | ||||
|       XIBarrierReleasePointer (priv->display->xdisplay, | ||||
|                                META_VIRTUAL_CORE_POINTER_ID, | ||||
|                                priv->xbarrier, event->event_id); | ||||
|       priv->release_event_id = 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 */ | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -192,19 +243,29 @@ meta_barrier_constructed (GObject *object) | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|   dpy = priv->display->xdisplay; | ||||
|   root = DefaultRootWindow (dpy); | ||||
|   if (meta_is_wayland_compositor ()) | ||||
|     { | ||||
|       MetaBarrierManager *manager = meta_barrier_manager_get (); | ||||
|  | ||||
|   priv->xbarrier = XFixesCreatePointerBarrier (dpy, root, | ||||
|                                                priv->x1, priv->y1, | ||||
|                                                priv->x2, priv->y2, | ||||
|                                                priv->directions, 0, NULL); | ||||
|       manager->barriers = g_list_prepend (manager->barriers, g_object_ref (barrier)); | ||||
|       priv->active = TRUE; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       dpy = priv->display->xdisplay; | ||||
|       root = DefaultRootWindow (dpy); | ||||
|  | ||||
|   /* 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); | ||||
|       priv->xbarrier = XFixesCreatePointerBarrier (dpy, root, | ||||
|                                                    priv->x1, priv->y1, | ||||
|                                                    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); | ||||
| } | ||||
| @@ -312,16 +373,26 @@ meta_barrier_destroy (MetaBarrier *barrier) | ||||
|   if (priv->display == NULL) | ||||
|     return; | ||||
|  | ||||
|   dpy = priv->display->xdisplay; | ||||
|   if (meta_is_wayland_compositor ()) | ||||
|     { | ||||
|       MetaBarrierManager *manager = meta_barrier_manager_get (); | ||||
|  | ||||
|   if (!meta_barrier_is_active (barrier)) | ||||
|     return; | ||||
|       manager->barriers = g_list_remove (manager->barriers, barrier); | ||||
|       g_object_unref (barrier); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       dpy = priv->display->xdisplay; | ||||
|  | ||||
|   XFixesDestroyPointerBarrier (dpy, priv->xbarrier); | ||||
|   g_hash_table_remove (priv->display->xids, &priv->xbarrier); | ||||
|   priv->xbarrier = 0; | ||||
|       if (!meta_barrier_is_active (barrier)) | ||||
|         return; | ||||
|  | ||||
|   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 | ||||
| @@ -371,6 +442,9 @@ meta_display_process_barrier_event (MetaDisplay    *display, | ||||
| { | ||||
|   MetaBarrier *barrier; | ||||
|  | ||||
|   if (meta_is_wayland_compositor ()) | ||||
|     return FALSE; | ||||
|  | ||||
|   barrier = g_hash_table_lookup (display->xids, &xev->barrier); | ||||
|   if (barrier != NULL) | ||||
|     { | ||||
| @@ -382,6 +456,405 @@ meta_display_process_barrier_event (MetaDisplay    *display, | ||||
| } | ||||
| #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 * | ||||
| meta_barrier_event_ref (MetaBarrierEvent *event) | ||||
| { | ||||
| @@ -399,7 +872,12 @@ meta_barrier_event_unref (MetaBarrierEvent *event) | ||||
|   g_return_if_fail (event->ref_count > 0); | ||||
|  | ||||
|   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, | ||||
|   | ||||
| @@ -1515,20 +1515,27 @@ guint32 | ||||
| meta_display_get_current_time_roundtrip (MetaDisplay *display) | ||||
| { | ||||
|   guint32 timestamp; | ||||
|    | ||||
|   timestamp = meta_display_get_current_time (display); | ||||
|   if (timestamp == CurrentTime) | ||||
|     { | ||||
|       XEvent property_event; | ||||
|  | ||||
|       XChangeProperty (display->xdisplay, display->timestamp_pinging_window, | ||||
|                        display->atom__MUTTER_TIMESTAMP_PING, | ||||
|                        XA_STRING, 8, PropModeAppend, NULL, 0); | ||||
|       XIfEvent (display->xdisplay, | ||||
|                 &property_event, | ||||
|                 find_timestamp_predicate, | ||||
|                 (XPointer) display); | ||||
|       timestamp = property_event.xproperty.time; | ||||
|   if (meta_is_wayland_compositor ()) | ||||
|     { | ||||
|       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, | ||||
|                            display->atom__MUTTER_TIMESTAMP_PING, | ||||
|                            XA_STRING, 8, PropModeAppend, NULL, 0); | ||||
|           XIfEvent (display->xdisplay, | ||||
|                     &property_event, | ||||
|                     find_timestamp_predicate, | ||||
|                     (XPointer) display); | ||||
|           timestamp = property_event.xproperty.time; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   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: | ||||
|  * @display: The MetaDisplay that events are coming from | ||||
| @@ -2962,6 +3003,10 @@ meta_display_handle_event (MetaDisplay *display, | ||||
|                 else if (event->xproperty.atom == | ||||
|                          display->atom__NET_DESKTOP_NAMES) | ||||
|                   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 | ||||
|                 else if (event->xproperty.atom == | ||||
|                          display->atom__NET_RESTACK_WINDOW) | ||||
| @@ -3197,7 +3242,9 @@ event_callback (XEvent  *event, | ||||
|      translation altogether by directly using the Clutter events */ | ||||
|   if (meta_is_wayland_compositor () && | ||||
|       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 meta_display_handle_event (display, event); | ||||
| @@ -6031,7 +6078,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display) | ||||
| gboolean | ||||
| 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; | ||||
|   const char *str; | ||||
|   MetaScreen *screen; | ||||
|   gboolean was_current_time; | ||||
|  | ||||
|   /* if key event was on root window, we have a shortcut */ | ||||
|   screen = meta_display_screen_for_root (display, event->event); | ||||
|  | ||||
|   /* 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 */ | ||||
|   /* We only ever have one screen */ | ||||
|   screen = display->screens->data; | ||||
|  | ||||
|   /* ignore key events on popup menus and such. */ | ||||
|   if (meta_ui_window_is_widget (screen->ui, event->event)) | ||||
|     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); | ||||
|  | ||||
| @@ -2098,11 +2098,11 @@ meta_display_process_key_event (MetaDisplay   *display, | ||||
|     { | ||||
|       handled = process_overlay_key (display, screen, event, keysym); | ||||
|       if (handled) | ||||
|         return TRUE; | ||||
|         goto out; | ||||
|  | ||||
|       handled = process_iso_next_group (display, screen, event, keysym); | ||||
|       if (handled) | ||||
|         return TRUE; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|   XIAllowEvents (display->xdisplay, event->deviceid, | ||||
| @@ -2112,7 +2112,11 @@ meta_display_process_key_event (MetaDisplay   *display, | ||||
|   if (all_keys_grabbed) | ||||
|     { | ||||
|       if (display->grab_op == META_GRAB_OP_NONE) | ||||
|         return TRUE; | ||||
|         { | ||||
|           handled = TRUE; | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       /* If we get here we have a global grab, because | ||||
|        * we're in some special keyboard mode such as window move | ||||
|        * mode. | ||||
| @@ -2191,14 +2195,20 @@ meta_display_process_key_event (MetaDisplay   *display, | ||||
|           meta_display_end_grab_op (display, event->time); | ||||
|         } | ||||
|  | ||||
|       return TRUE; | ||||
|       handled = TRUE; | ||||
|       goto out; | ||||
|     } | ||||
|  | ||||
|   /* Do the normal keybindings */ | ||||
|   return process_event (display->key_bindings, | ||||
|                         display->n_key_bindings, | ||||
|                         display, screen, window, event, keysym, | ||||
|                         !all_keys_grabbed && window); | ||||
|   handled = process_event (display->key_bindings, | ||||
|                            display->n_key_bindings, | ||||
|                            display, screen, window, event, keysym, | ||||
|                            !all_keys_grabbed && window); | ||||
|  | ||||
|  out: | ||||
|   if (was_current_time) | ||||
|     display->current_time = CurrentTime; | ||||
|   return handled; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
|   | ||||
| @@ -401,6 +401,9 @@ meta_init (void) | ||||
|                 g_strerror (errno)); | ||||
| #endif | ||||
|  | ||||
|   if (getenv ("MUTTER_SLEEP_INIT")) | ||||
|     sleep (60); | ||||
|  | ||||
|   g_unix_signal_add (SIGTERM, on_sigterm, NULL); | ||||
|  | ||||
|   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); | ||||
| } | ||||
|  | ||||
| /* 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 | ||||
| meta_prop_set_utf8_string_hint (MetaDisplay *display, | ||||
|                                 Window xwindow, | ||||
|   | ||||
| @@ -102,6 +102,11 @@ gboolean meta_prop_get_utf8_list     (MetaDisplay   *display, | ||||
|                                       Atom           xatom, | ||||
|                                       char        ***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 | ||||
|                                      (MetaDisplay *display, | ||||
|                                       Window xwindow, | ||||
|   | ||||
| @@ -81,6 +81,7 @@ item(TIMESTAMP) | ||||
| item(VERSION) | ||||
| item(ATOM_PAIR) | ||||
| item(BACKLIGHT) | ||||
| item(_XKB_RULES_NAMES) | ||||
|  | ||||
| /* Oddities: These are used, and we need atoms for them, | ||||
|  * but when we need all _NET_WM hints (i.e. when we're making | ||||
|   | ||||
| @@ -94,6 +94,7 @@ typedef enum { | ||||
| struct _MetaBarrierEvent { | ||||
|   /* < private > */ | ||||
|   volatile guint ref_count; | ||||
|   MetaBarrier *barrier; | ||||
|  | ||||
|   /* < public > */ | ||||
|   int event_id; | ||||
|   | ||||
| @@ -106,11 +106,49 @@ create_anonymous_file (off_t size, | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info) | ||||
| static void | ||||
| 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; | ||||
|   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_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); | ||||
|   if (keymap_str == NULL) | ||||
|     { | ||||
|       g_warning ("failed to get string version of keymap\n"); | ||||
|       return FALSE; | ||||
|       g_warning ("failed to get string version of keymap"); | ||||
|       return; | ||||
|     } | ||||
|   previous_size = xkb_info->keymap_size; | ||||
|   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); | ||||
|   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, | ||||
|                  error->message); | ||||
|       g_clear_error (&error); | ||||
|       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, | ||||
|                                 PROT_READ | PROT_WRITE, | ||||
|                                 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); | ||||
|   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: | ||||
|   close (xkb_info->keymap_fd); | ||||
|   xkb_info->keymap_fd = -1; | ||||
| err_keymap_str: | ||||
|   free (keymap_str); | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|   return; | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -306,9 +334,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, | ||||
|                             struct wl_display   *display, | ||||
| 			    gboolean             is_evdev) | ||||
| { | ||||
|   ClutterDeviceManager *manager; | ||||
|  | ||||
|   memset (keyboard, 0, sizeof *keyboard); | ||||
|   keyboard->xkb_info.keymap_fd = -1; | ||||
|  | ||||
|   wl_list_init (&keyboard->resource_list); | ||||
|   wl_array_init (&keyboard->keys); | ||||
| @@ -320,18 +347,15 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, | ||||
|   keyboard->display = display; | ||||
|  | ||||
|   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; | ||||
|   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; | ||||
| } | ||||
| @@ -388,6 +412,81 @@ set_modifiers (MetaWaylandKeyboard *keyboard, | ||||
|                               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 | ||||
| update_pressed_keys (MetaWaylandKeyboard   *keyboard, | ||||
| 		     uint32_t               evdev_code, | ||||
| @@ -460,6 +559,10 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, | ||||
| 		autorepeat ? " (autorepeat)" : "", | ||||
| 		xkb_keycode); | ||||
|  | ||||
|   /* Give a chance to process keybindings */ | ||||
|   if (process_keybinding (keyboard, (ClutterEvent*) event)) | ||||
|     return TRUE; | ||||
|  | ||||
|   if (autorepeat) | ||||
|     return FALSE; | ||||
|  | ||||
| @@ -559,12 +662,6 @@ meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard) | ||||
| void | ||||
| 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); | ||||
|   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); | ||||
| } | ||||
|  | ||||
| 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; | ||||
|   gboolean is_evdev; | ||||
|   MetaWaylandXkbInfo xkb_info; | ||||
|   struct xkb_rule_names xkb_names; | ||||
|  | ||||
|   MetaWaylandKeyboardGrab input_method_grab; | ||||
|   struct wl_resource *input_method_resource; | ||||
| @@ -123,6 +122,18 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, | ||||
|                             struct wl_display   *display, | ||||
| 			    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 | ||||
| meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, | ||||
|                                     const ClutterKeyEvent *event); | ||||
|   | ||||
| @@ -49,6 +49,7 @@ | ||||
|  | ||||
| #include "meta-wayland-pointer.h" | ||||
| #include "meta-wayland-private.h" | ||||
| #include "barrier-private.h" | ||||
|  | ||||
| #include <string.h> | ||||
|  | ||||
| @@ -165,10 +166,10 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = { | ||||
|  */ | ||||
|  | ||||
| static gboolean | ||||
| check_all_screen_monitors(MetaMonitorInfo *monitors, | ||||
| 			  unsigned         n_monitors, | ||||
| 			  float            x, | ||||
| 			  float            y) | ||||
| check_all_screen_monitors (MetaMonitorInfo *monitors, | ||||
| 			   unsigned         n_monitors, | ||||
| 			   float            x, | ||||
| 			   float            y) | ||||
| { | ||||
|   unsigned int i; | ||||
|  | ||||
| @@ -193,14 +194,13 @@ static void | ||||
| constrain_all_screen_monitors (ClutterInputDevice *device, | ||||
| 			       MetaMonitorInfo    *monitors, | ||||
| 			       unsigned            n_monitors, | ||||
| 			       float               current_x, | ||||
| 			       float               current_y, | ||||
| 			       float              *x, | ||||
| 			       float              *y) | ||||
| { | ||||
|   ClutterPoint current; | ||||
|   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 */ | ||||
|   for (i = 0; i < n_monitors; i++) | ||||
|     { | ||||
| @@ -213,8 +213,8 @@ constrain_all_screen_monitors (ClutterInputDevice *device, | ||||
|       top = monitor->rect.y; | ||||
|       bottom = left + monitor->rect.height; | ||||
|  | ||||
|       nx = current.x; | ||||
|       ny = current.y; | ||||
|       nx = current_x; | ||||
|       ny = current_y; | ||||
|  | ||||
|       if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom)) | ||||
| 	{ | ||||
| @@ -239,21 +239,32 @@ pointer_constrain_callback (ClutterInputDevice *device, | ||||
| 			    float              *new_y, | ||||
| 			    gpointer            user_data) | ||||
| { | ||||
|   MetaBarrierManager *barrier_manager; | ||||
|   MetaMonitorManager *monitor_manager; | ||||
|   MetaMonitorInfo *monitors; | ||||
|   unsigned int n_monitors; | ||||
|   gboolean ret; | ||||
|   ClutterPoint current; | ||||
|  | ||||
|   clutter_input_device_get_coords (device, NULL, ¤t); | ||||
|  | ||||
|   barrier_manager = meta_barrier_manager_get (); | ||||
|   monitor_manager = meta_monitor_manager_get (); | ||||
|   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 */ | ||||
|   ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y); | ||||
|   if (ret == TRUE) | ||||
|   if (ret) | ||||
|     return; | ||||
|  | ||||
|   /* 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 | ||||
|   | ||||
| @@ -697,12 +697,7 @@ event_cb (ClutterActor *stage, | ||||
|  | ||||
|       if (surface && surface->window && | ||||
| 	  surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND) | ||||
|         { | ||||
| 	  MetaDisplay *display = meta_get_display (); | ||||
| 	  guint32 timestamp = meta_display_get_current_time_roundtrip (display); | ||||
|  | ||||
| 	  meta_window_focus (surface->window, timestamp); | ||||
|         } | ||||
| 	meta_window_focus (surface->window, clutter_event_get_time (event)); | ||||
|     } | ||||
|  | ||||
|   if (seat->cursor_tracker) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user