Compare commits
	
		
			6 Commits
		
	
	
		
			wip/carlos
			...
			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