Compare commits
	
		
			72 Commits
		
	
	
		
			3.11.90
			...
			wip/waylan
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e2c768d682 | ||
| 
						 | 
					a67c12e873 | ||
| 
						 | 
					1dd31d67ab | ||
| 
						 | 
					b1419e2966 | ||
| 
						 | 
					6924e760c4 | ||
| 
						 | 
					fa9e90fe25 | ||
| 
						 | 
					806d9ddb22 | ||
| 
						 | 
					a8425496ad | ||
| 
						 | 
					e9434732d4 | ||
| 
						 | 
					bbf07c9b17 | ||
| 
						 | 
					804c2be976 | ||
| 
						 | 
					9bdcc9c418 | ||
| 
						 | 
					cee22daf55 | ||
| 
						 | 
					63fdf8bcb8 | ||
| 
						 | 
					62442cf0ce | ||
| 
						 | 
					c1549af840 | ||
| 
						 | 
					8325f0eda5 | ||
| 
						 | 
					14931ed391 | ||
| 
						 | 
					c06762518e | ||
| 
						 | 
					8483dec921 | ||
| 
						 | 
					d7e970cb0a | ||
| 
						 | 
					b383d55988 | ||
| 
						 | 
					25f82424b8 | ||
| 
						 | 
					7764e1f3ff | ||
| 
						 | 
					ce3ec40036 | ||
| 
						 | 
					22a668f2cf | ||
| 
						 | 
					97ff406102 | ||
| 
						 | 
					e2f06dfa8c | ||
| 
						 | 
					ee6b729196 | ||
| 
						 | 
					0d1647cbc4 | ||
| 
						 | 
					49a83138f4 | ||
| 
						 | 
					1e3aad2d8c | ||
| 
						 | 
					33c0c1dc18 | ||
| 
						 | 
					e261f0ac39 | ||
| 
						 | 
					528219fcbf | ||
| 
						 | 
					d9a5f2638a | ||
| 
						 | 
					738b0eee1d | ||
| 
						 | 
					0480d6c898 | ||
| 
						 | 
					2777dfc533 | ||
| 
						 | 
					cf296f26b1 | ||
| 
						 | 
					b8f6801d20 | ||
| 
						 | 
					2a1c0429dd | ||
| 
						 | 
					5ae9457176 | ||
| 
						 | 
					e158500ef0 | ||
| 
						 | 
					b29d8046b0 | ||
| 
						 | 
					fa3ca2bf10 | ||
| 
						 | 
					fc42b478bd | ||
| 
						 | 
					0e0e0a4c7e | ||
| 
						 | 
					c96fd23e79 | ||
| 
						 | 
					045d03014d | ||
| 
						 | 
					a83049c103 | ||
| 
						 | 
					5f4121830c | ||
| 
						 | 
					43d499318f | ||
| 
						 | 
					f2fab33551 | ||
| 
						 | 
					0e098249b1 | ||
| 
						 | 
					9a5f243f73 | ||
| 
						 | 
					03f55b9485 | ||
| 
						 | 
					ef9ef87d91 | ||
| 
						 | 
					0ee2c21da7 | ||
| 
						 | 
					9b966561c4 | ||
| 
						 | 
					8c0779a9db | ||
| 
						 | 
					2c901cc015 | ||
| 
						 | 
					85e66f69fa | ||
| 
						 | 
					a5585327dc | ||
| 
						 | 
					268ebb1b18 | ||
| 
						 | 
					40e820f551 | ||
| 
						 | 
					f9a11b3b18 | ||
| 
						 | 
					bd3c357212 | ||
| 
						 | 
					b4d108dac6 | ||
| 
						 | 
					6585a5760b | ||
| 
						 | 
					531be6c413 | ||
| 
						 | 
					f0c503b5a9 | 
@@ -1,5 +1,5 @@
 | 
			
		||||
 | 
			
		||||
SUBDIRS=src po doc
 | 
			
		||||
SUBDIRS=src protocol data po doc
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = HACKING MAINTAINERS rationales.txt
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ srcdir=`dirname $0`
 | 
			
		||||
test -z "$srcdir" && srcdir=.
 | 
			
		||||
 | 
			
		||||
PKG_NAME="mutter"
 | 
			
		||||
REQUIRED_AUTOMAKE_VERSION=1.10
 | 
			
		||||
REQUIRED_AUTOMAKE_VERSION=1.13
 | 
			
		||||
 | 
			
		||||
(test -f $srcdir/configure.ac \
 | 
			
		||||
  && test -d $srcdir/src) || {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								configure.ac
									
									
									
									
									
								
							@@ -15,7 +15,7 @@ AC_INIT([mutter], [mutter_version],
 | 
			
		||||
AC_CONFIG_SRCDIR(src/core/display.c)
 | 
			
		||||
AC_CONFIG_HEADERS(config.h)
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar])
 | 
			
		||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar])
 | 
			
		||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
 | 
			
		||||
AM_MAINTAINER_MODE([enable])
 | 
			
		||||
 | 
			
		||||
@@ -75,6 +75,7 @@ MUTTER_PC_MODULES="
 | 
			
		||||
   xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
 | 
			
		||||
   $CLUTTER_PACKAGE >= 1.14.3
 | 
			
		||||
   cogl-1.0 >= 1.13.3
 | 
			
		||||
   upower-glib > 0.9.11
 | 
			
		||||
"
 | 
			
		||||
 | 
			
		||||
GLIB_GSETTINGS
 | 
			
		||||
@@ -113,11 +114,32 @@ AC_ARG_ENABLE(shape,
 | 
			
		||||
                 [disable mutter's use of the shaped window extension]),,
 | 
			
		||||
  enable_shape=auto)
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(wayland,
 | 
			
		||||
  AC_HELP_STRING([--enable-wayland],
 | 
			
		||||
                 [Enable support for running as a hybrid X and Wayland compositor]),,
 | 
			
		||||
  enable_wayland=no)
 | 
			
		||||
 | 
			
		||||
## Wayland support requires the xserver.xml protocol extension found in the weston
 | 
			
		||||
## repository but since there aren't currently established conventions for
 | 
			
		||||
## installing and discovering these we simply require a location to be given
 | 
			
		||||
## explicitly...
 | 
			
		||||
AC_ARG_WITH([wayland-protocols],
 | 
			
		||||
            [AS_HELP_STRING([--with-wayland-protocols], [Location for wayland extension protocol specs])],
 | 
			
		||||
            [
 | 
			
		||||
            ],
 | 
			
		||||
            [])
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH([xwayland-path],
 | 
			
		||||
            [AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])],
 | 
			
		||||
            [XWAYLAND_PATH="$withval"],
 | 
			
		||||
            [XWAYLAND_PATH="$bindir/Xorg"])
 | 
			
		||||
 | 
			
		||||
AM_GLIB_GNU_GETTEXT
 | 
			
		||||
 | 
			
		||||
## here we get the flags we'll actually use
 | 
			
		||||
# GRegex requires Glib-2.14.0
 | 
			
		||||
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
 | 
			
		||||
 | 
			
		||||
# Unconditionally use this dir to avoid a circular dep with gnomecc
 | 
			
		||||
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
 | 
			
		||||
@@ -196,6 +218,29 @@ if test x$have_xcursor = xyes; then
 | 
			
		||||
  AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
have_wayland=no
 | 
			
		||||
if test x$enable_wayland = "xyes"; then
 | 
			
		||||
  WAYLAND_VERSION=0.1
 | 
			
		||||
  AC_MSG_CHECKING([Wayland >= $WAYLAND_VERSION])
 | 
			
		||||
  if ! $PKG_CONFIG --atleast-version $WAYLAND_VERSION wayland-server; then
 | 
			
		||||
    AC_MSG_ERROR([wayland support enabled but no suitable wayland-server package found])
 | 
			
		||||
  fi
 | 
			
		||||
  AC_MSG_RESULT(yes)
 | 
			
		||||
 | 
			
		||||
  AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
 | 
			
		||||
  AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
 | 
			
		||||
        AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
 | 
			
		||||
  AC_SUBST([WAYLAND_SCANNER])
 | 
			
		||||
 | 
			
		||||
  AC_SUBST(XWAYLAND_PATH)
 | 
			
		||||
 | 
			
		||||
  MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server libdrm"
 | 
			
		||||
  AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
 | 
			
		||||
  have_wayland=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AM_CONDITIONAL(HAVE_WAYLAND, test x$have_wayland = "xyes")
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
 | 
			
		||||
@@ -436,6 +481,8 @@ src/Makefile
 | 
			
		||||
src/libmutter.pc
 | 
			
		||||
src/mutter-plugins.pc
 | 
			
		||||
src/compositor/plugins/Makefile
 | 
			
		||||
protocol/Makefile
 | 
			
		||||
data/Makefile
 | 
			
		||||
po/Makefile.in
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
@@ -457,6 +504,8 @@ mutter-$VERSION
 | 
			
		||||
	source code location:	  ${srcdir}
 | 
			
		||||
	compiler:		  ${CC}
 | 
			
		||||
 | 
			
		||||
	Wayland:		  ${have_wayland}
 | 
			
		||||
 | 
			
		||||
	Startup notification:     ${have_startup_notification}
 | 
			
		||||
	libcanberra:              ${have_libcanberra}
 | 
			
		||||
	Introspection:            ${found_introspection}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								data/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								data/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
defaultcursordir = $(datadir)/mutter/cursors
 | 
			
		||||
 | 
			
		||||
dist_defaultcursor_DATA =
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
dist_defaultcursor_DATA += left_ptr.png
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								data/left_ptr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/left_ptr.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 736 B  | 
							
								
								
									
										1
									
								
								protocol/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								protocol/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
EXTRA_DIST = xserver.xml
 | 
			
		||||
							
								
								
									
										18
									
								
								protocol/xserver.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								protocol/xserver.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
<protocol name="xserver">
 | 
			
		||||
 | 
			
		||||
  <interface name="xserver" version="1">
 | 
			
		||||
    <request name="set_window_id">
 | 
			
		||||
      <arg name="surface" type="object" interface="wl_surface"/>
 | 
			
		||||
      <arg name="id" type="uint"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="client">
 | 
			
		||||
      <arg name="fd" type="fd"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="listen_socket">
 | 
			
		||||
      <arg name="fd" type="fd"/>
 | 
			
		||||
    </event>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
</protocol>
 | 
			
		||||
@@ -29,10 +29,25 @@ INCLUDES=								\
 | 
			
		||||
	-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\"			\
 | 
			
		||||
	-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
INCLUDES += \
 | 
			
		||||
	-I$(srcdir)/wayland						\
 | 
			
		||||
	-DXWAYLAND_PATH='"@XWAYLAND_PATH@"'
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
mutter_built_sources = \
 | 
			
		||||
	$(dbus_xrandr_built_sources)	\
 | 
			
		||||
	$(dbus_idle_built_sources) \
 | 
			
		||||
	mutter-enum-types.h \
 | 
			
		||||
	mutter-enum-types.c
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
mutter_built_sources += \
 | 
			
		||||
	wayland/xserver-protocol.c		\
 | 
			
		||||
	wayland/xserver-server-protocol.h	\
 | 
			
		||||
	wayland/xserver-client-protocol.h
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
libmutter_la_SOURCES =				\
 | 
			
		||||
	core/async-getprop.c			\
 | 
			
		||||
	core/async-getprop.h			\
 | 
			
		||||
@@ -110,6 +125,16 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	core/keybindings.c			\
 | 
			
		||||
	core/keybindings-private.h		\
 | 
			
		||||
	core/main.c				\
 | 
			
		||||
	core/meta-cursor-tracker.c		\
 | 
			
		||||
	core/meta-cursor-tracker-private.h	\
 | 
			
		||||
	core/meta-idle-monitor.c		\
 | 
			
		||||
	core/meta-idle-monitor-private.h	\
 | 
			
		||||
	core/meta-xrandr-shared.h		\
 | 
			
		||||
	core/monitor.c				\
 | 
			
		||||
	core/monitor-config.c			\
 | 
			
		||||
	core/monitor-kms.c			\
 | 
			
		||||
	core/monitor-private.h			\
 | 
			
		||||
	core/monitor-xrandr.c			\
 | 
			
		||||
	core/mutter-Xatomtype.h			\
 | 
			
		||||
	core/place.c				\
 | 
			
		||||
	core/place.h				\
 | 
			
		||||
@@ -158,6 +183,28 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	ui/ui.c					\
 | 
			
		||||
	$(mutter_built_sources)
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
libmutter_la_SOURCES +=				\
 | 
			
		||||
	wayland/meta-tty.c			\
 | 
			
		||||
	wayland/meta-tty.h			\
 | 
			
		||||
	wayland/meta-wayland.c			\
 | 
			
		||||
	wayland/meta-wayland-private.h		\
 | 
			
		||||
	wayland/meta-xwayland-private.h		\
 | 
			
		||||
	wayland/meta-xwayland.c			\
 | 
			
		||||
	wayland/meta-wayland-data-device.c      \
 | 
			
		||||
	wayland/meta-wayland-data-device.h      \
 | 
			
		||||
	wayland/meta-wayland-keyboard.c		\
 | 
			
		||||
	wayland/meta-wayland-keyboard.h		\
 | 
			
		||||
	wayland/meta-wayland-pointer.c		\
 | 
			
		||||
	wayland/meta-wayland-pointer.h		\
 | 
			
		||||
	wayland/meta-wayland-seat.c		\
 | 
			
		||||
	wayland/meta-wayland-seat.h		\
 | 
			
		||||
	wayland/meta-wayland-stage.h		\
 | 
			
		||||
	wayland/meta-wayland-stage.c		\
 | 
			
		||||
	wayland/meta-weston-launch.c		\
 | 
			
		||||
	wayland/meta-weston-launch.h
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
libmutter_la_LDFLAGS = -no-undefined
 | 
			
		||||
libmutter_la_LIBADD  = $(MUTTER_LIBS)
 | 
			
		||||
 | 
			
		||||
@@ -178,6 +225,8 @@ libmutterinclude_base_headers =		\
 | 
			
		||||
	meta/meta-background-actor.h		\
 | 
			
		||||
	meta/meta-background-group.h		\
 | 
			
		||||
	meta/meta-background.h			\
 | 
			
		||||
	meta/meta-cursor-tracker.h		\
 | 
			
		||||
	meta/meta-idle-monitor.h		\
 | 
			
		||||
	meta/meta-plugin.h			\
 | 
			
		||||
	meta/meta-shaped-texture.h		\
 | 
			
		||||
	meta/meta-shadow-factory.h		\
 | 
			
		||||
@@ -206,6 +255,19 @@ bin_PROGRAMS=mutter
 | 
			
		||||
mutter_SOURCES = core/mutter.c
 | 
			
		||||
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
bin_PROGRAMS+=mutter-launch
 | 
			
		||||
 | 
			
		||||
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
 | 
			
		||||
 | 
			
		||||
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS)
 | 
			
		||||
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
 | 
			
		||||
 | 
			
		||||
install-exec-hook:
 | 
			
		||||
	-chown root $(DESTDIR)$(bindir)/mutter-launch
 | 
			
		||||
	-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if HAVE_INTROSPECTION
 | 
			
		||||
include $(INTROSPECTION_MAKEFILE)
 | 
			
		||||
 | 
			
		||||
@@ -323,3 +385,31 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
 | 
			
		||||
	  $(libmutterinclude_base_headers) ) >> xgen-tetc && \
 | 
			
		||||
	cp xgen-tetc mutter-enum-types.c && \
 | 
			
		||||
	rm -f xgen-tetc
 | 
			
		||||
 | 
			
		||||
dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
 | 
			
		||||
 | 
			
		||||
$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
 | 
			
		||||
	$(AM_V_GEN)gdbus-codegen							\
 | 
			
		||||
		--interface-prefix org.gnome.Mutter					\
 | 
			
		||||
		--c-namespace MetaDBus							\
 | 
			
		||||
		--generate-c-code meta-dbus-xrandr					\
 | 
			
		||||
		xrandr.xml
 | 
			
		||||
 | 
			
		||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
 | 
			
		||||
 | 
			
		||||
$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
 | 
			
		||||
	$(AM_V_GEN)gdbus-codegen							\
 | 
			
		||||
		--interface-prefix org.gnome.Mutter					\
 | 
			
		||||
		--c-namespace MetaDBus							\
 | 
			
		||||
		--generate-c-code meta-dbus-idle-monitor				\
 | 
			
		||||
		--c-generate-object-manager						\
 | 
			
		||||
		idle-monitor.xml
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 | 
			
		||||
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
 | 
			
		||||
wayland/%-client-protocol.h : $(top_builddir)/protocol/%.xml
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
@@ -66,8 +66,6 @@ void meta_switch_workspace_completed (MetaScreen    *screen);
 | 
			
		||||
 | 
			
		||||
gboolean meta_begin_modal_for_plugin (MetaScreen       *screen,
 | 
			
		||||
                                      MetaPlugin       *plugin,
 | 
			
		||||
                                      Window            grab_window,
 | 
			
		||||
                                      Cursor            cursor,
 | 
			
		||||
                                      MetaModalOptions  options,
 | 
			
		||||
                                      guint32           timestamp);
 | 
			
		||||
void     meta_end_modal_for_plugin   (MetaScreen       *screen,
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,11 @@
 | 
			
		||||
#include "meta-window-group.h"
 | 
			
		||||
#include "window-private.h" /* to check window->hidden */
 | 
			
		||||
#include "display-private.h" /* for meta_display_lookup_x_window() */
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
#include "meta-wayland-keyboard.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include <X11/extensions/shape.h>
 | 
			
		||||
#include <X11/extensions/Xcomposite.h>
 | 
			
		||||
 | 
			
		||||
@@ -172,7 +177,7 @@ process_damage (MetaCompositor     *compositor,
 | 
			
		||||
  if (window_actor == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_process_damage (window_actor, event);
 | 
			
		||||
  meta_window_actor_process_x11_damage (window_actor, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -327,29 +332,37 @@ void
 | 
			
		||||
meta_set_stage_input_region (MetaScreen   *screen,
 | 
			
		||||
                             XserverRegion region)
 | 
			
		||||
{
 | 
			
		||||
  MetaCompScreen *info = meta_screen_get_compositor_data (screen);
 | 
			
		||||
  MetaDisplay  *display = meta_screen_get_display (screen);
 | 
			
		||||
  Display      *xdpy    = meta_display_get_xdisplay (display);
 | 
			
		||||
  /* As a wayland compositor we can simply ignore all this trickery
 | 
			
		||||
   * for setting an input region on the stage for capturing events in
 | 
			
		||||
   * clutter since all input comes to us first and we get to choose
 | 
			
		||||
   * who else sees them.
 | 
			
		||||
   */
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      MetaCompScreen *info = meta_screen_get_compositor_data (screen);
 | 
			
		||||
      MetaDisplay  *display = meta_screen_get_display (screen);
 | 
			
		||||
      Display      *xdpy    = meta_display_get_xdisplay (display);
 | 
			
		||||
 | 
			
		||||
  if (info->stage && info->output)
 | 
			
		||||
    {
 | 
			
		||||
      do_set_stage_input_region (screen, region);
 | 
			
		||||
      if (info->stage && info->output)
 | 
			
		||||
        {
 | 
			
		||||
          do_set_stage_input_region (screen, region);
 | 
			
		||||
        }
 | 
			
		||||
      else 
 | 
			
		||||
        {
 | 
			
		||||
          /* Reset info->pending_input_region if one existed before and set the new
 | 
			
		||||
           * one to use it later. */ 
 | 
			
		||||
          if (info->pending_input_region)
 | 
			
		||||
            {
 | 
			
		||||
              XFixesDestroyRegion (xdpy, info->pending_input_region);
 | 
			
		||||
              info->pending_input_region = None;
 | 
			
		||||
            }
 | 
			
		||||
          if (region != None)
 | 
			
		||||
            {
 | 
			
		||||
              info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
 | 
			
		||||
              XFixesCopyRegion (xdpy, info->pending_input_region, region);
 | 
			
		||||
            }
 | 
			
		||||
        } 
 | 
			
		||||
    }
 | 
			
		||||
  else 
 | 
			
		||||
    {
 | 
			
		||||
      /* Reset info->pending_input_region if one existed before and set the new
 | 
			
		||||
       * one to use it later. */ 
 | 
			
		||||
      if (info->pending_input_region)
 | 
			
		||||
        {
 | 
			
		||||
          XFixesDestroyRegion (xdpy, info->pending_input_region);
 | 
			
		||||
          info->pending_input_region = None;
 | 
			
		||||
        }
 | 
			
		||||
      if (region != None)
 | 
			
		||||
        {
 | 
			
		||||
          info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
 | 
			
		||||
          XFixesCopyRegion (xdpy, info->pending_input_region, region);
 | 
			
		||||
        }
 | 
			
		||||
    } 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -380,56 +393,55 @@ meta_focus_stage_window (MetaScreen *screen,
 | 
			
		||||
  if (!stage)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  window = clutter_x11_get_stage_window (stage);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      window = clutter_x11_get_stage_window (stage);
 | 
			
		||||
 | 
			
		||||
  if (window == None)
 | 
			
		||||
    return;
 | 
			
		||||
      if (window == None)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
  meta_display_set_input_focus_xwindow (screen->display,
 | 
			
		||||
                                        screen,
 | 
			
		||||
                                        window,
 | 
			
		||||
                                        timestamp);
 | 
			
		||||
      meta_display_set_input_focus_xwindow (screen->display,
 | 
			
		||||
                                            screen,
 | 
			
		||||
                                            META_FOCUS_STAGE,
 | 
			
		||||
                                            window,
 | 
			
		||||
                                            timestamp);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_display_set_input_focus_xwindow (screen->display,
 | 
			
		||||
                                            screen,
 | 
			
		||||
                                            META_FOCUS_STAGE,
 | 
			
		||||
                                            None,
 | 
			
		||||
                                            timestamp);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_stage_is_focused (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  ClutterStage *stage;
 | 
			
		||||
  Window window;
 | 
			
		||||
 | 
			
		||||
  stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
 | 
			
		||||
  if (!stage)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  window = clutter_x11_get_stage_window (stage);
 | 
			
		||||
 | 
			
		||||
  if (window == None)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return (screen->display->focus_xwindow == window);
 | 
			
		||||
  return (screen->display->focus_type == META_FOCUS_STAGE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_begin_modal_for_plugin (MetaScreen       *screen,
 | 
			
		||||
                             MetaPlugin       *plugin,
 | 
			
		||||
                             Window            grab_window,
 | 
			
		||||
                             Cursor            cursor,
 | 
			
		||||
                             MetaModalOptions  options,
 | 
			
		||||
                             guint32           timestamp)
 | 
			
		||||
static gboolean
 | 
			
		||||
begin_modal_x11 (MetaScreen       *screen,
 | 
			
		||||
                 MetaPlugin       *plugin,
 | 
			
		||||
                 MetaModalOptions  options,
 | 
			
		||||
                 guint32           timestamp)
 | 
			
		||||
{
 | 
			
		||||
  /* To some extent this duplicates code in meta_display_begin_grab_op(), but there
 | 
			
		||||
   * are significant differences in how we handle grabs that make it difficult to
 | 
			
		||||
   * merge the two.
 | 
			
		||||
   */
 | 
			
		||||
  MetaDisplay    *display    = meta_screen_get_display (screen);
 | 
			
		||||
  Display        *xdpy       = meta_display_get_xdisplay (display);
 | 
			
		||||
  MetaCompositor *compositor = display->compositor;
 | 
			
		||||
  gboolean pointer_grabbed = FALSE;
 | 
			
		||||
  gboolean keyboard_grabbed = FALSE;
 | 
			
		||||
  int result;
 | 
			
		||||
 | 
			
		||||
  if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  MetaDisplay    *display     = meta_screen_get_display (screen);
 | 
			
		||||
  Display        *xdpy        = meta_display_get_xdisplay (display);
 | 
			
		||||
  MetaCompScreen *info        = meta_screen_get_compositor_data (screen);
 | 
			
		||||
  Window          grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
 | 
			
		||||
  Cursor          cursor      = None;
 | 
			
		||||
  int             result;
 | 
			
		||||
  gboolean        pointer_grabbed = FALSE;
 | 
			
		||||
  gboolean        keyboard_grabbed = FALSE;
 | 
			
		||||
 | 
			
		||||
  if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
 | 
			
		||||
    {
 | 
			
		||||
@@ -479,14 +491,6 @@ meta_begin_modal_for_plugin (MetaScreen       *screen,
 | 
			
		||||
      keyboard_grabbed = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  display->grab_op = META_GRAB_OP_COMPOSITOR;
 | 
			
		||||
  display->grab_window = NULL;
 | 
			
		||||
  display->grab_screen = screen;
 | 
			
		||||
  display->grab_have_pointer = TRUE;
 | 
			
		||||
  display->grab_have_keyboard = TRUE;
 | 
			
		||||
 | 
			
		||||
  compositor->modal_plugin = plugin;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
@@ -498,6 +502,79 @@ meta_begin_modal_for_plugin (MetaScreen       *screen,
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
begin_modal_wayland (MetaScreen       *screen,
 | 
			
		||||
                     MetaPlugin       *plugin,
 | 
			
		||||
                     MetaModalOptions  options,
 | 
			
		||||
                     guint32           timestamp)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
  gboolean pointer_grabbed = FALSE;
 | 
			
		||||
  gboolean keyboard_grabbed = FALSE;
 | 
			
		||||
 | 
			
		||||
  compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
 | 
			
		||||
  if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
      pointer_grabbed = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard))
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
      keyboard_grabbed = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
  if (pointer_grabbed)
 | 
			
		||||
    meta_wayland_pointer_end_modal (&compositor->seat->pointer);
 | 
			
		||||
  if (keyboard_grabbed)
 | 
			
		||||
    meta_wayland_keyboard_end_modal (&compositor->seat->keyboard);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_begin_modal_for_plugin (MetaScreen       *screen,
 | 
			
		||||
                             MetaPlugin       *plugin,
 | 
			
		||||
                             MetaModalOptions  options,
 | 
			
		||||
                             guint32           timestamp)
 | 
			
		||||
{
 | 
			
		||||
  /* To some extent this duplicates code in meta_display_begin_grab_op(), but there
 | 
			
		||||
   * are significant differences in how we handle grabs that make it difficult to
 | 
			
		||||
   * merge the two.
 | 
			
		||||
   */
 | 
			
		||||
  MetaDisplay    *display    = meta_screen_get_display (screen);
 | 
			
		||||
  MetaCompositor *compositor = display->compositor;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
 | 
			
		||||
  if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    ok = begin_modal_wayland (screen, plugin, options, timestamp);
 | 
			
		||||
  else
 | 
			
		||||
    ok = begin_modal_x11 (screen, plugin, options, timestamp);
 | 
			
		||||
  if (!ok)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  display->grab_op = META_GRAB_OP_COMPOSITOR;
 | 
			
		||||
  display->grab_window = NULL;
 | 
			
		||||
  display->grab_screen = screen;
 | 
			
		||||
  display->grab_have_pointer = TRUE;
 | 
			
		||||
  display->grab_have_keyboard = TRUE;
 | 
			
		||||
 | 
			
		||||
  compositor->modal_plugin = plugin;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_end_modal_for_plugin (MetaScreen     *screen,
 | 
			
		||||
                           MetaPlugin     *plugin,
 | 
			
		||||
@@ -509,8 +586,18 @@ meta_end_modal_for_plugin (MetaScreen     *screen,
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (compositor->modal_plugin == plugin);
 | 
			
		||||
 | 
			
		||||
  XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
 | 
			
		||||
  XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
 | 
			
		||||
      meta_wayland_pointer_end_modal (&compositor->seat->pointer);
 | 
			
		||||
      meta_wayland_keyboard_end_modal (&compositor->seat->keyboard);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
 | 
			
		||||
      XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  display->grab_op = META_GRAB_OP_NONE;
 | 
			
		||||
  display->grab_window = NULL;
 | 
			
		||||
@@ -562,6 +649,11 @@ redirect_windows (MetaCompositor *compositor,
 | 
			
		||||
  guint        n_retries;
 | 
			
		||||
  guint        max_retries;
 | 
			
		||||
 | 
			
		||||
  /* If we're running with wayland, connected to a headless xwayland
 | 
			
		||||
   * server then all the windows are implicitly redirected offscreen
 | 
			
		||||
   * already and it would generate an error to try and explicitly
 | 
			
		||||
   * redirect them via XCompositeRedirectSubwindows() */
 | 
			
		||||
 | 
			
		||||
  if (meta_get_replace_current_wm ())
 | 
			
		||||
    max_retries = 5;
 | 
			
		||||
  else
 | 
			
		||||
@@ -602,8 +694,11 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 | 
			
		||||
  MetaCompScreen *info;
 | 
			
		||||
  MetaDisplay    *display       = meta_screen_get_display (screen);
 | 
			
		||||
  Display        *xdisplay      = meta_display_get_xdisplay (display);
 | 
			
		||||
  Window          xwin;
 | 
			
		||||
  Window          xwin          = None;
 | 
			
		||||
  gint            width, height;
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  MetaWaylandCompositor *wayland_compositor;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Check if the screen is already managed */
 | 
			
		||||
  if (meta_screen_get_compositor_data (screen))
 | 
			
		||||
@@ -616,7 +711,14 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 | 
			
		||||
   * We have to initialize info->pending_input_region to an empty region explicitly, 
 | 
			
		||||
   * because None value is used to mean that the whole screen is an input region.
 | 
			
		||||
   */
 | 
			
		||||
  info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Stage input region trickery isn't needed when we're running as a
 | 
			
		||||
       * wayland compositor. */
 | 
			
		||||
      info->pending_input_region = None;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  info->screen = screen;
 | 
			
		||||
 | 
			
		||||
@@ -627,7 +729,58 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 | 
			
		||||
 | 
			
		||||
  meta_screen_set_cm_selection (screen);
 | 
			
		||||
 | 
			
		||||
  info->stage = clutter_stage_new ();
 | 
			
		||||
  /* We will have already created a stage if running as a wayland
 | 
			
		||||
   * compositor... */
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      wayland_compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
      info->stage = wayland_compositor->stage;
 | 
			
		||||
 | 
			
		||||
      meta_screen_get_size (screen, &width, &height);
 | 
			
		||||
      clutter_actor_set_size (info->stage, width, height);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
#endif /* HAVE_WAYLAND */
 | 
			
		||||
    {
 | 
			
		||||
      info->stage = clutter_stage_new ();
 | 
			
		||||
 | 
			
		||||
      meta_screen_get_size (screen, &width, &height);
 | 
			
		||||
      clutter_actor_realize (info->stage);
 | 
			
		||||
 | 
			
		||||
      xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
 | 
			
		||||
 | 
			
		||||
      XResizeWindow (xdisplay, xwin, width, height);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
          long event_mask;
 | 
			
		||||
          unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
 | 
			
		||||
          XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
 | 
			
		||||
          XWindowAttributes attr;
 | 
			
		||||
 | 
			
		||||
          meta_core_add_old_event_mask (xdisplay, xwin, &mask);
 | 
			
		||||
 | 
			
		||||
          XISetMask (mask.mask, XI_KeyPress);
 | 
			
		||||
          XISetMask (mask.mask, XI_KeyRelease);
 | 
			
		||||
          XISetMask (mask.mask, XI_ButtonPress);
 | 
			
		||||
          XISetMask (mask.mask, XI_ButtonRelease);
 | 
			
		||||
          XISetMask (mask.mask, XI_Enter);
 | 
			
		||||
          XISetMask (mask.mask, XI_Leave);
 | 
			
		||||
          XISetMask (mask.mask, XI_FocusIn);
 | 
			
		||||
          XISetMask (mask.mask, XI_FocusOut);
 | 
			
		||||
          XISetMask (mask.mask, XI_Motion);
 | 
			
		||||
          XIClearMask (mask.mask, XI_TouchBegin);
 | 
			
		||||
          XIClearMask (mask.mask, XI_TouchEnd);
 | 
			
		||||
          XIClearMask (mask.mask, XI_TouchUpdate);
 | 
			
		||||
          XISelectEvents (xdisplay, xwin, &mask, 1);
 | 
			
		||||
 | 
			
		||||
          event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask;
 | 
			
		||||
          if (XGetWindowAttributes (xdisplay, xwin, &attr))
 | 
			
		||||
            event_mask |= attr.your_event_mask;
 | 
			
		||||
 | 
			
		||||
          XSelectInput (xdisplay, xwin, event_mask);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  clutter_stage_set_paint_callback (CLUTTER_STAGE (info->stage),
 | 
			
		||||
                                    after_stage_paint,
 | 
			
		||||
@@ -636,42 +789,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 | 
			
		||||
 | 
			
		||||
  clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY);
 | 
			
		||||
 | 
			
		||||
  meta_screen_get_size (screen, &width, &height);
 | 
			
		||||
  clutter_actor_realize (info->stage);
 | 
			
		||||
 | 
			
		||||
  xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
 | 
			
		||||
 | 
			
		||||
  XResizeWindow (xdisplay, xwin, width, height);
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    long event_mask;
 | 
			
		||||
    unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
 | 
			
		||||
    XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
 | 
			
		||||
    XWindowAttributes attr;
 | 
			
		||||
 | 
			
		||||
    meta_core_add_old_event_mask (xdisplay, xwin, &mask);
 | 
			
		||||
 | 
			
		||||
    XISetMask (mask.mask, XI_KeyPress);
 | 
			
		||||
    XISetMask (mask.mask, XI_KeyRelease);
 | 
			
		||||
    XISetMask (mask.mask, XI_ButtonPress);
 | 
			
		||||
    XISetMask (mask.mask, XI_ButtonRelease);
 | 
			
		||||
    XISetMask (mask.mask, XI_Enter);
 | 
			
		||||
    XISetMask (mask.mask, XI_Leave);
 | 
			
		||||
    XISetMask (mask.mask, XI_FocusIn);
 | 
			
		||||
    XISetMask (mask.mask, XI_FocusOut);
 | 
			
		||||
    XISetMask (mask.mask, XI_Motion);
 | 
			
		||||
    XIClearMask (mask.mask, XI_TouchBegin);
 | 
			
		||||
    XIClearMask (mask.mask, XI_TouchEnd);
 | 
			
		||||
    XIClearMask (mask.mask, XI_TouchUpdate);
 | 
			
		||||
    XISelectEvents (xdisplay, xwin, &mask, 1);
 | 
			
		||||
 | 
			
		||||
    event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask;
 | 
			
		||||
    if (XGetWindowAttributes (xdisplay, xwin, &attr))
 | 
			
		||||
      event_mask |= attr.your_event_mask;
 | 
			
		||||
 | 
			
		||||
    XSelectInput (xdisplay, xwin, event_mask);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  info->window_group = meta_window_group_new (screen);
 | 
			
		||||
  info->top_window_group = meta_window_group_new (screen);
 | 
			
		||||
 | 
			
		||||
@@ -680,53 +797,68 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
 | 
			
		||||
 | 
			
		||||
  info->plugin_mgr = meta_plugin_manager_new (screen);
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Delay the creation of the overlay window as long as we can, to avoid
 | 
			
		||||
   * blanking out the screen. This means that during the plugin loading, the
 | 
			
		||||
   * overlay window is not accessible; if the plugin needs to access it
 | 
			
		||||
   * directly, it should hook into the "show" signal on stage, and do
 | 
			
		||||
   * its stuff there.
 | 
			
		||||
   */
 | 
			
		||||
  info->output = get_output_window (screen);
 | 
			
		||||
  XReparentWindow (xdisplay, xwin, info->output, 0, 0);
 | 
			
		||||
 | 
			
		||||
 /* Make sure there isn't any left-over output shape on the 
 | 
			
		||||
  * overlay window by setting the whole screen to be an
 | 
			
		||||
  * output region.
 | 
			
		||||
  * 
 | 
			
		||||
  * Note: there doesn't seem to be any real chance of that
 | 
			
		||||
  *  because the X server will destroy the overlay window
 | 
			
		||||
  *  when the last client using it exits.
 | 
			
		||||
  */
 | 
			
		||||
  XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
 | 
			
		||||
 | 
			
		||||
  do_set_stage_input_region (screen, info->pending_input_region);
 | 
			
		||||
  if (info->pending_input_region != None)
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      XFixesDestroyRegion (xdisplay, info->pending_input_region);
 | 
			
		||||
      info->pending_input_region = None;
 | 
			
		||||
      /* NB: When running as a wayland compositor we don't need an X
 | 
			
		||||
       * composite overlay window, and we don't need to play any input
 | 
			
		||||
       * region tricks to redirect events into clutter. */
 | 
			
		||||
      info->output = None;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /*
 | 
			
		||||
       * Delay the creation of the overlay window as long as we can, to avoid
 | 
			
		||||
       * blanking out the screen. This means that during the plugin loading, the
 | 
			
		||||
       * overlay window is not accessible; if the plugin needs to access it
 | 
			
		||||
       * directly, it should hook into the "show" signal on stage, and do
 | 
			
		||||
       * its stuff there.
 | 
			
		||||
       */
 | 
			
		||||
      info->output = get_output_window (screen);
 | 
			
		||||
      XReparentWindow (xdisplay, xwin, info->output, 0, 0);
 | 
			
		||||
 | 
			
		||||
      /* Make sure there isn't any left-over output shape on the 
 | 
			
		||||
       * overlay window by setting the whole screen to be an
 | 
			
		||||
       * output region.
 | 
			
		||||
       * 
 | 
			
		||||
       * Note: there doesn't seem to be any real chance of that
 | 
			
		||||
       *  because the X server will destroy the overlay window
 | 
			
		||||
       *  when the last client using it exits.
 | 
			
		||||
       */
 | 
			
		||||
      XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
 | 
			
		||||
 | 
			
		||||
      do_set_stage_input_region (screen, info->pending_input_region);
 | 
			
		||||
      if (info->pending_input_region != None)
 | 
			
		||||
        {
 | 
			
		||||
          XFixesDestroyRegion (xdisplay, info->pending_input_region);
 | 
			
		||||
          info->pending_input_region = None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Map overlay window before redirecting windows offscreen so we catch their
 | 
			
		||||
       * contents until we show the stage.
 | 
			
		||||
       */
 | 
			
		||||
      XMapWindow (xdisplay, info->output);
 | 
			
		||||
 | 
			
		||||
      redirect_windows (compositor, screen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Map overlay window before redirecting windows offscreen so we catch their
 | 
			
		||||
   * contents until we show the stage.
 | 
			
		||||
   */
 | 
			
		||||
  XMapWindow (xdisplay, info->output);
 | 
			
		||||
 | 
			
		||||
  redirect_windows (compositor, screen);
 | 
			
		||||
  clutter_actor_show (info->stage);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_compositor_unmanage_screen (MetaCompositor *compositor,
 | 
			
		||||
                                 MetaScreen     *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay    *display       = meta_screen_get_display (screen);
 | 
			
		||||
  Display        *xdisplay      = meta_display_get_xdisplay (display);
 | 
			
		||||
  Window          xroot         = meta_screen_get_xroot (screen);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      MetaDisplay    *display       = meta_screen_get_display (screen);
 | 
			
		||||
      Display        *xdisplay      = meta_display_get_xdisplay (display);
 | 
			
		||||
      Window          xroot         = meta_screen_get_xroot (screen);
 | 
			
		||||
 | 
			
		||||
  /* This is the most important part of cleanup - we have to do this
 | 
			
		||||
   * before giving up the window manager selection or the next
 | 
			
		||||
   * window manager won't be able to redirect subwindows */
 | 
			
		||||
  XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
 | 
			
		||||
      /* This is the most important part of cleanup - we have to do this
 | 
			
		||||
       * before giving up the window manager selection or the next
 | 
			
		||||
       * window manager won't be able to redirect subwindows */
 | 
			
		||||
      XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -798,15 +930,18 @@ meta_compositor_remove_window (MetaCompositor *compositor,
 | 
			
		||||
  if (!window_actor)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  screen = meta_window_get_screen (window);
 | 
			
		||||
  info = meta_screen_get_compositor_data (screen);
 | 
			
		||||
 | 
			
		||||
  if (window_actor == info->unredirected_window)
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_actor_set_redirected (window_actor, TRUE);
 | 
			
		||||
      meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
 | 
			
		||||
                                 NULL);
 | 
			
		||||
      info->unredirected_window = NULL;
 | 
			
		||||
      screen = meta_window_get_screen (window);
 | 
			
		||||
      info = meta_screen_get_compositor_data (screen);
 | 
			
		||||
 | 
			
		||||
      if (window_actor == info->unredirected_window)
 | 
			
		||||
        {
 | 
			
		||||
          meta_window_actor_set_redirected (window_actor, TRUE);
 | 
			
		||||
          meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
 | 
			
		||||
                                     NULL);
 | 
			
		||||
          info->unredirected_window = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_destroy (window_actor);
 | 
			
		||||
@@ -866,8 +1001,8 @@ is_grabbed_event (MetaDisplay *display,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_compositor_window_shape_changed (MetaCompositor *compositor,
 | 
			
		||||
                                      MetaWindow     *window)
 | 
			
		||||
meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
 | 
			
		||||
                                          MetaWindow     *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActor *window_actor;
 | 
			
		||||
  window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
 | 
			
		||||
@@ -993,7 +1128,8 @@ meta_compositor_process_event (MetaCompositor *compositor,
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
 | 
			
		||||
      if (!meta_is_wayland_compositor () &&
 | 
			
		||||
          event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
 | 
			
		||||
        {
 | 
			
		||||
          /* Core code doesn't handle damage events, so we need to extract the MetaWindow
 | 
			
		||||
           * ourselves
 | 
			
		||||
@@ -1012,7 +1148,7 @@ meta_compositor_process_event (MetaCompositor *compositor,
 | 
			
		||||
 | 
			
		||||
  /* Clutter needs to know about MapNotify events otherwise it will
 | 
			
		||||
     think the stage is invisible */
 | 
			
		||||
  if (event->type == MapNotify)
 | 
			
		||||
  if (!meta_is_wayland_compositor () && event->type == MapNotify)
 | 
			
		||||
    clutter_x11_handle_event (event);
 | 
			
		||||
 | 
			
		||||
  /* The above handling is basically just "observing" the events, so we return
 | 
			
		||||
@@ -1354,22 +1490,40 @@ meta_compositor_sync_screen_size (MetaCompositor  *compositor,
 | 
			
		||||
				  guint		   width,
 | 
			
		||||
				  guint		   height)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay    *display = meta_screen_get_display (screen);
 | 
			
		||||
  MetaCompScreen *info    = meta_screen_get_compositor_data (screen);
 | 
			
		||||
  Display        *xdisplay;
 | 
			
		||||
  Window          xwin;
 | 
			
		||||
 | 
			
		||||
  DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
 | 
			
		||||
  g_return_if_fail (info);
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      /* FIXME: when we support a sliced stage, this is the place to do it
 | 
			
		||||
         But! This is not the place to apply KMS config, here we only
 | 
			
		||||
         notify Clutter/Cogl/GL that the framebuffer sizes changed.
 | 
			
		||||
 | 
			
		||||
  xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
  xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
 | 
			
		||||
         And because for now clutter does not do sliced, we use one
 | 
			
		||||
         framebuffer the size of the whole screen, and when running on
 | 
			
		||||
         bare metal MetaMonitorManager will do the necessary tricks to
 | 
			
		||||
         show the right portions on the right screens.
 | 
			
		||||
      */
 | 
			
		||||
 | 
			
		||||
  XResizeWindow (xdisplay, xwin, width, height);
 | 
			
		||||
      clutter_actor_set_size (info->stage, width, height);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      MetaDisplay    *display = meta_screen_get_display (screen);
 | 
			
		||||
      Display        *xdisplay;
 | 
			
		||||
      Window          xwin;
 | 
			
		||||
 | 
			
		||||
      DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
 | 
			
		||||
      g_return_if_fail (info);
 | 
			
		||||
 | 
			
		||||
      xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
      xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
 | 
			
		||||
 | 
			
		||||
      XResizeWindow (xdisplay, xwin, width, height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
 | 
			
		||||
		meta_screen_get_screen_number (screen),
 | 
			
		||||
		width, height);
 | 
			
		||||
                meta_screen_get_screen_number (screen),
 | 
			
		||||
                width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -1433,29 +1587,32 @@ pre_paint_windows (MetaCompScreen *info)
 | 
			
		||||
  if (info->windows == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  top_window = g_list_last (info->windows)->data;
 | 
			
		||||
 | 
			
		||||
  if (meta_window_actor_should_unredirect (top_window) &&
 | 
			
		||||
      info->disable_unredirect_count == 0)
 | 
			
		||||
    expected_unredirected_window = top_window;
 | 
			
		||||
 | 
			
		||||
  if (info->unredirected_window != expected_unredirected_window)
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      if (info->unredirected_window != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          meta_window_actor_set_redirected (info->unredirected_window, TRUE);
 | 
			
		||||
          meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
 | 
			
		||||
                                     NULL);
 | 
			
		||||
        }
 | 
			
		||||
      top_window = g_list_last (info->windows)->data;
 | 
			
		||||
 | 
			
		||||
      if (expected_unredirected_window != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)),
 | 
			
		||||
                                     meta_window_actor_get_meta_window (top_window));
 | 
			
		||||
          meta_window_actor_set_redirected (top_window, FALSE);
 | 
			
		||||
        }
 | 
			
		||||
      if (meta_window_actor_should_unredirect (top_window) &&
 | 
			
		||||
          info->disable_unredirect_count == 0)
 | 
			
		||||
        expected_unredirected_window = top_window;
 | 
			
		||||
 | 
			
		||||
      info->unredirected_window = expected_unredirected_window;
 | 
			
		||||
      if (info->unredirected_window != expected_unredirected_window)
 | 
			
		||||
        {
 | 
			
		||||
          if (info->unredirected_window != NULL)
 | 
			
		||||
            {
 | 
			
		||||
              meta_window_actor_set_redirected (info->unredirected_window, TRUE);
 | 
			
		||||
              meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
 | 
			
		||||
                                         NULL);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (expected_unredirected_window != NULL)
 | 
			
		||||
            {
 | 
			
		||||
              meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)),
 | 
			
		||||
                                         meta_window_actor_get_meta_window (top_window));
 | 
			
		||||
              meta_window_actor_set_redirected (top_window, FALSE);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          info->unredirected_window = expected_unredirected_window;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (l = info->windows; l; l = l->next)
 | 
			
		||||
 
 | 
			
		||||
@@ -85,12 +85,20 @@ meta_plugin_manager_load (const gchar       *plugin_name)
 | 
			
		||||
  g_free (path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_confirm_display_change (MetaMonitorManager *monitors,
 | 
			
		||||
                           MetaPluginManager  *plugin_mgr)
 | 
			
		||||
{
 | 
			
		||||
  meta_plugin_manager_confirm_display_change (plugin_mgr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaPluginManager *
 | 
			
		||||
meta_plugin_manager_new (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaPluginManager *plugin_mgr;
 | 
			
		||||
  MetaPluginClass *klass;
 | 
			
		||||
  MetaPlugin *plugin;
 | 
			
		||||
  MetaMonitorManager *monitors;
 | 
			
		||||
 | 
			
		||||
  plugin_mgr = g_new0 (MetaPluginManager, 1);
 | 
			
		||||
  plugin_mgr->screen = screen;
 | 
			
		||||
@@ -101,6 +109,10 @@ meta_plugin_manager_new (MetaScreen *screen)
 | 
			
		||||
  if (klass->start)
 | 
			
		||||
    klass->start (plugin);
 | 
			
		||||
 | 
			
		||||
  monitors = meta_monitor_manager_get ();
 | 
			
		||||
  g_signal_connect (monitors, "confirm-display-change",
 | 
			
		||||
                    G_CALLBACK (on_confirm_display_change), plugin_mgr);
 | 
			
		||||
 | 
			
		||||
  return plugin_mgr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -317,6 +329,28 @@ meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
 | 
			
		||||
   */
 | 
			
		||||
  if (klass->xevent_filter)
 | 
			
		||||
    return klass->xevent_filter (plugin, xev);
 | 
			
		||||
  else
 | 
			
		||||
    return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
 | 
			
		||||
 | 
			
		||||
  /* When mutter is running as a wayland compositor, things like input
 | 
			
		||||
   * events just come directly from clutter so it won't have disabled
 | 
			
		||||
   * clutter's event retrieval and won't need to forward it events (if
 | 
			
		||||
   * it did it would lead to recursion). Also when running as a
 | 
			
		||||
   * wayland compositor we shouldn't be assuming that we're running
 | 
			
		||||
   * with the clutter x11 backend.
 | 
			
		||||
   */
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr)
 | 
			
		||||
{
 | 
			
		||||
  MetaPlugin *plugin = plugin_mgr->plugin;
 | 
			
		||||
  MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
 | 
			
		||||
 | 
			
		||||
  if (klass->confirm_display_change)
 | 
			
		||||
    return klass->confirm_display_change (plugin);
 | 
			
		||||
  else
 | 
			
		||||
    return meta_plugin_complete_display_change (plugin, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -73,4 +73,6 @@ gboolean meta_plugin_manager_filter_keybinding (MetaPluginManager  *mgr,
 | 
			
		||||
gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr,
 | 
			
		||||
                                            XEvent            *xev);
 | 
			
		||||
 | 
			
		||||
void     meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@
 | 
			
		||||
 | 
			
		||||
#include "compositor-private.h"
 | 
			
		||||
#include "meta-window-actor-private.h"
 | 
			
		||||
#include "monitor-private.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
@@ -266,10 +267,6 @@ meta_plugin_destroy_completed (MetaPlugin      *plugin,
 | 
			
		||||
/**
 | 
			
		||||
 * meta_plugin_begin_modal:
 | 
			
		||||
 * @plugin: a #MetaPlugin
 | 
			
		||||
 * @grab_window: the X window to grab the keyboard and mouse on
 | 
			
		||||
 * @cursor: the cursor to use for the pointer grab, or None,
 | 
			
		||||
 *          to use the normal cursor for the grab window and
 | 
			
		||||
 *          its descendants.
 | 
			
		||||
 * @options: flags that modify the behavior of the modal grab
 | 
			
		||||
 * @timestamp: the timestamp used for establishing grabs
 | 
			
		||||
 *
 | 
			
		||||
@@ -290,15 +287,13 @@ meta_plugin_destroy_completed (MetaPlugin      *plugin,
 | 
			
		||||
 */
 | 
			
		||||
gboolean
 | 
			
		||||
meta_plugin_begin_modal (MetaPlugin       *plugin,
 | 
			
		||||
                         Window            grab_window,
 | 
			
		||||
                         Cursor            cursor,
 | 
			
		||||
                         MetaModalOptions  options,
 | 
			
		||||
                         guint32           timestamp)
 | 
			
		||||
{
 | 
			
		||||
  MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
 | 
			
		||||
 | 
			
		||||
  return meta_begin_modal_for_plugin (priv->screen, plugin,
 | 
			
		||||
                                      grab_window, cursor, options, timestamp);
 | 
			
		||||
                                      options, timestamp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -338,3 +333,13 @@ meta_plugin_get_screen (MetaPlugin *plugin)
 | 
			
		||||
 | 
			
		||||
  return priv->screen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_plugin_complete_display_change (MetaPlugin *plugin,
 | 
			
		||||
                                     gboolean    ok)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *manager;
 | 
			
		||||
 | 
			
		||||
  manager = meta_monitor_manager_get ();
 | 
			
		||||
  meta_monitor_manager_confirm_configuration (manager, ok);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,14 @@
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/meta-shaped-texture.h>
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
#include "meta-texture-tower.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include <cogl/cogl-wayland-server.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <cogl/cogl.h>
 | 
			
		||||
#include <cogl/cogl-texture-pixmap-x11.h>
 | 
			
		||||
@@ -55,6 +61,15 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
 | 
			
		||||
 | 
			
		||||
static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
 | 
			
		||||
 | 
			
		||||
typedef enum _MetaShapedTextureType
 | 
			
		||||
{
 | 
			
		||||
  META_SHAPED_TEXTURE_TYPE_X11_PIXMAP,
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE,
 | 
			
		||||
#endif
 | 
			
		||||
} MetaShapedTextureType;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
 | 
			
		||||
               CLUTTER_TYPE_ACTOR);
 | 
			
		||||
 | 
			
		||||
@@ -65,13 +80,27 @@ G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
 | 
			
		||||
struct _MetaShapedTexturePrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaTextureTower *paint_tower;
 | 
			
		||||
  Pixmap pixmap;
 | 
			
		||||
  CoglTexturePixmapX11 *texture;
 | 
			
		||||
 | 
			
		||||
  MetaShapedTextureType type;
 | 
			
		||||
  union {
 | 
			
		||||
    struct {
 | 
			
		||||
      Pixmap pixmap;
 | 
			
		||||
    } x11;
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
    struct {
 | 
			
		||||
      MetaWaylandSurface *surface;
 | 
			
		||||
    } wayland;
 | 
			
		||||
#endif
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  CoglTexture *texture;
 | 
			
		||||
 | 
			
		||||
  CoglTexture *mask_texture;
 | 
			
		||||
  CoglPipeline *pipeline;
 | 
			
		||||
  CoglPipeline *pipeline_unshaped;
 | 
			
		||||
 | 
			
		||||
  cairo_region_t *clip_region;
 | 
			
		||||
  cairo_region_t *input_shape_region;
 | 
			
		||||
 | 
			
		||||
  guint tex_width, tex_height;
 | 
			
		||||
 | 
			
		||||
@@ -103,7 +132,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
 | 
			
		||||
  priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
 | 
			
		||||
 | 
			
		||||
  priv->paint_tower = meta_texture_tower_new ();
 | 
			
		||||
 | 
			
		||||
  priv->type = META_SHAPED_TEXTURE_TYPE_X11_PIXMAP;
 | 
			
		||||
  priv->texture = NULL;
 | 
			
		||||
 | 
			
		||||
  priv->mask_texture = NULL;
 | 
			
		||||
  priv->create_mipmaps = TRUE;
 | 
			
		||||
}
 | 
			
		||||
@@ -128,6 +160,56 @@ meta_shaped_texture_dispose (GObject *object)
 | 
			
		||||
  G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_cogl_texture (MetaShapedTexture *stex,
 | 
			
		||||
                  CoglTexture       *cogl_tex)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
  guint width, height;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->texture)
 | 
			
		||||
    cogl_object_unref (priv->texture);
 | 
			
		||||
 | 
			
		||||
  priv->texture = cogl_tex;
 | 
			
		||||
 | 
			
		||||
  if (priv->pipeline != NULL)
 | 
			
		||||
    cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
 | 
			
		||||
 | 
			
		||||
  if (priv->pipeline_unshaped != NULL)
 | 
			
		||||
    cogl_pipeline_set_layer_texture (priv->pipeline_unshaped, 0, COGL_TEXTURE (cogl_tex));
 | 
			
		||||
 | 
			
		||||
  if (cogl_tex != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
 | 
			
		||||
      height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
 | 
			
		||||
 | 
			
		||||
      if (width != priv->tex_width ||
 | 
			
		||||
          height != priv->tex_height)
 | 
			
		||||
        {
 | 
			
		||||
          priv->tex_width = width;
 | 
			
		||||
          priv->tex_height = height;
 | 
			
		||||
 | 
			
		||||
          clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* size changed to 0 going to an invalid handle */
 | 
			
		||||
      priv->tex_width = 0;
 | 
			
		||||
      priv->tex_height = 0;
 | 
			
		||||
      clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* NB: We don't queue a redraw of the actor here because we don't
 | 
			
		||||
   * know how much of the buffer has changed with respect to the
 | 
			
		||||
   * previous buffer. We only queue a redraw in response to surface
 | 
			
		||||
   * damage. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_shaped_texture_paint (ClutterActor *actor)
 | 
			
		||||
{
 | 
			
		||||
@@ -285,38 +367,53 @@ meta_shaped_texture_pick (ClutterActor       *actor,
 | 
			
		||||
  MetaShapedTexture *stex = (MetaShapedTexture *) actor;
 | 
			
		||||
  MetaShapedTexturePrivate *priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (!clutter_actor_should_pick_paint (actor) ||
 | 
			
		||||
      (priv->clip_region && cairo_region_is_empty (priv->clip_region)))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* If there is no region then use the regular pick */
 | 
			
		||||
  if (priv->mask_texture == NULL)
 | 
			
		||||
  if (priv->input_shape_region == NULL)
 | 
			
		||||
    CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
 | 
			
		||||
      ->pick (actor, color);
 | 
			
		||||
  else if (clutter_actor_should_pick_paint (actor))
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      CoglTexture *paint_tex;
 | 
			
		||||
      ClutterActorBox alloc;
 | 
			
		||||
      guint tex_width, tex_height;
 | 
			
		||||
      int n_rects;
 | 
			
		||||
      float *rectangles;
 | 
			
		||||
      int i;
 | 
			
		||||
 | 
			
		||||
      paint_tex = COGL_TEXTURE (priv->texture);
 | 
			
		||||
      /* Note: We don't bother trying to intersect the pick and clip regions
 | 
			
		||||
       * since needing to copy the region, do the intersection, and probably
 | 
			
		||||
       * increase the number of rectangles seems more likely to have a negative
 | 
			
		||||
       * effect.
 | 
			
		||||
       *
 | 
			
		||||
       * NB: Most of the time when just using rectangles for picking then
 | 
			
		||||
       * picking shouldn't involve any rendering, and minimizing the number of
 | 
			
		||||
       * rectangles has more benefit than reducing the area of the pick
 | 
			
		||||
       * region.
 | 
			
		||||
       */
 | 
			
		||||
 | 
			
		||||
      if (paint_tex == NULL)
 | 
			
		||||
        return;
 | 
			
		||||
      n_rects = cairo_region_num_rectangles (priv->input_shape_region);
 | 
			
		||||
      rectangles = g_alloca (sizeof (float) * 4 * n_rects);
 | 
			
		||||
 | 
			
		||||
      tex_width = cogl_texture_get_width (paint_tex);
 | 
			
		||||
      tex_height = cogl_texture_get_height (paint_tex);
 | 
			
		||||
      for (i = 0; i < n_rects; i++)
 | 
			
		||||
        {
 | 
			
		||||
          cairo_rectangle_int_t rect;
 | 
			
		||||
          int pos = i * 4;
 | 
			
		||||
 | 
			
		||||
      if (tex_width == 0 || tex_height == 0) /* no contents yet */
 | 
			
		||||
        return;
 | 
			
		||||
          cairo_region_get_rectangle (priv->input_shape_region, i, &rect);
 | 
			
		||||
 | 
			
		||||
      cogl_set_source_color4ub (color->red, color->green, color->blue,
 | 
			
		||||
                                 color->alpha);
 | 
			
		||||
          rectangles[pos] = rect.x;
 | 
			
		||||
          rectangles[pos + 1] = rect.y;
 | 
			
		||||
          rectangles[pos + 2] = rect.x + rect.width;
 | 
			
		||||
          rectangles[pos + 3] = rect.y + rect.height;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      clutter_actor_get_allocation_box (actor, &alloc);
 | 
			
		||||
      cogl_set_source_color4ub (color->red,
 | 
			
		||||
                                color->green,
 | 
			
		||||
                                color->blue,
 | 
			
		||||
                                color->alpha);
 | 
			
		||||
 | 
			
		||||
      /* Paint the mask rectangle in the given color */
 | 
			
		||||
      cogl_set_source_texture (priv->mask_texture);
 | 
			
		||||
      cogl_rectangle_with_texture_coords (0, 0,
 | 
			
		||||
                                          alloc.x2 - alloc.x1,
 | 
			
		||||
                                          alloc.y2 - alloc.y1,
 | 
			
		||||
                                          0, 0, 1, 1);
 | 
			
		||||
      cogl_rectangles (rectangles, n_rects);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -365,12 +462,48 @@ meta_shaped_texture_get_paint_volume (ClutterActor *self,
 | 
			
		||||
  return clutter_paint_volume_set_from_allocation (volume, self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
ClutterActor *
 | 
			
		||||
meta_shaped_texture_new (void)
 | 
			
		||||
meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
 | 
			
		||||
  ClutterActor *actor = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
 | 
			
		||||
  MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (actor)->priv;
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
  /* XXX: it could probably be better to have a "type" construct-only
 | 
			
		||||
   * property or create wayland/x11 subclasses */
 | 
			
		||||
  priv->type = META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE;
 | 
			
		||||
 | 
			
		||||
  meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (actor),
 | 
			
		||||
                                           surface);
 | 
			
		||||
 | 
			
		||||
  return actor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
 | 
			
		||||
                                         MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  priv->wayland.surface = surface;
 | 
			
		||||
 | 
			
		||||
  if (surface && surface->buffer_ref.buffer)
 | 
			
		||||
    meta_shaped_texture_attach_wayland_buffer (stex,
 | 
			
		||||
                                               surface->buffer_ref.buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandSurface *
 | 
			
		||||
meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv = stex->priv;
 | 
			
		||||
  return priv->wayland.surface;
 | 
			
		||||
}
 | 
			
		||||
#endif /* HAVE_WAYLAND */
 | 
			
		||||
 | 
			
		||||
ClutterActor *
 | 
			
		||||
meta_shaped_texture_new_with_xwindow (Window xwindow)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -389,8 +522,7 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
 | 
			
		||||
    {
 | 
			
		||||
      CoglTexture *base_texture;
 | 
			
		||||
      priv->create_mipmaps = create_mipmaps;
 | 
			
		||||
      base_texture = create_mipmaps ?
 | 
			
		||||
        COGL_TEXTURE (priv->texture) : NULL;
 | 
			
		||||
      base_texture = create_mipmaps ? priv->texture : NULL;
 | 
			
		||||
      meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -416,74 +548,146 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
 | 
			
		||||
  clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_shaped_texture_update_area (MetaShapedTexture *stex,
 | 
			
		||||
				 int                x,
 | 
			
		||||
				 int                y,
 | 
			
		||||
				 int                width,
 | 
			
		||||
				 int                height)
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
static void
 | 
			
		||||
wayland_surface_update_area (MetaShapedTexture *stex,
 | 
			
		||||
                             int                x,
 | 
			
		||||
                             int                y,
 | 
			
		||||
                             int                width,
 | 
			
		||||
                             int                height)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
  MetaWaylandBuffer *buffer;
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (priv->type == META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE);
 | 
			
		||||
  g_return_if_fail (priv->texture != NULL);
 | 
			
		||||
 | 
			
		||||
  buffer = priv->wayland.surface->buffer_ref.buffer;
 | 
			
		||||
 | 
			
		||||
  if (buffer)
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_resource *resource = buffer->resource;
 | 
			
		||||
      struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
 | 
			
		||||
 | 
			
		||||
      if (shm_buffer)
 | 
			
		||||
        {
 | 
			
		||||
          CoglPixelFormat format;
 | 
			
		||||
 | 
			
		||||
          switch (wl_shm_buffer_get_format (shm_buffer))
 | 
			
		||||
            {
 | 
			
		||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
 | 
			
		||||
            case WL_SHM_FORMAT_ARGB8888:
 | 
			
		||||
              format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
 | 
			
		||||
              break;
 | 
			
		||||
            case WL_SHM_FORMAT_XRGB8888:
 | 
			
		||||
              format = COGL_PIXEL_FORMAT_ARGB_8888;
 | 
			
		||||
              break;
 | 
			
		||||
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
 | 
			
		||||
            case WL_SHM_FORMAT_ARGB8888:
 | 
			
		||||
              format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
 | 
			
		||||
              break;
 | 
			
		||||
            case WL_SHM_FORMAT_XRGB8888:
 | 
			
		||||
              format = COGL_PIXEL_FORMAT_BGRA_8888;
 | 
			
		||||
              break;
 | 
			
		||||
#endif
 | 
			
		||||
            default:
 | 
			
		||||
              g_warn_if_reached ();
 | 
			
		||||
              format = COGL_PIXEL_FORMAT_ARGB_8888;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          cogl_texture_set_region (priv->texture,
 | 
			
		||||
                                   x, y,
 | 
			
		||||
                                   x, y,
 | 
			
		||||
                                   width, height,
 | 
			
		||||
                                   width, height,
 | 
			
		||||
                                   format,
 | 
			
		||||
                                   wl_shm_buffer_get_stride (shm_buffer),
 | 
			
		||||
                                   wl_shm_buffer_get_data (shm_buffer));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif /* HAVE_WAYLAND */
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
queue_damage_redraw_with_clip (MetaShapedTexture *stex,
 | 
			
		||||
                               int x,
 | 
			
		||||
                               int y,
 | 
			
		||||
                               int width,
 | 
			
		||||
                               int height)
 | 
			
		||||
{
 | 
			
		||||
  ClutterActor *self = CLUTTER_ACTOR (stex);
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
  ClutterActorBox allocation;
 | 
			
		||||
  float scale_x;
 | 
			
		||||
  float scale_y;
 | 
			
		||||
  cairo_rectangle_int_t clip;
 | 
			
		||||
 | 
			
		||||
  /* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's
 | 
			
		||||
   * coordinate space so we need to convert from surface coordinates to
 | 
			
		||||
   * actor coordinates...
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  /* Calling clutter_actor_get_allocation_box() is enormously expensive
 | 
			
		||||
   * if the actor has an out-of-date allocation, since it triggers
 | 
			
		||||
   * a full redraw. clutter_actor_queue_redraw_with_clip() would redraw
 | 
			
		||||
   * the whole stage anyways in that case, so just go ahead and do
 | 
			
		||||
   * it here.
 | 
			
		||||
   */
 | 
			
		||||
  if (!clutter_actor_has_allocation (self))
 | 
			
		||||
    {
 | 
			
		||||
      clutter_actor_queue_redraw (self);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->tex_width == 0 || priv->tex_height == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  clutter_actor_get_allocation_box (self, &allocation);
 | 
			
		||||
 | 
			
		||||
  scale_x = (allocation.x2 - allocation.x1) / priv->tex_width;
 | 
			
		||||
  scale_y = (allocation.y2 - allocation.y1) / priv->tex_height;
 | 
			
		||||
 | 
			
		||||
  clip.x = x * scale_x;
 | 
			
		||||
  clip.y = y * scale_y;
 | 
			
		||||
  clip.width = width * scale_x;
 | 
			
		||||
  clip.height = height * scale_y;
 | 
			
		||||
  clutter_actor_queue_redraw_with_clip (self, &clip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_shaped_texture_update_area (MetaShapedTexture *stex,
 | 
			
		||||
                                 int                x,
 | 
			
		||||
                                 int                y,
 | 
			
		||||
                                 int                width,
 | 
			
		||||
                                 int                height)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
  const cairo_rectangle_int_t clip = { x, y, width, height };
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->texture == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  cogl_texture_pixmap_x11_update_area (priv->texture,
 | 
			
		||||
                                       x, y, width, height);
 | 
			
		||||
  switch (priv->type)
 | 
			
		||||
    {
 | 
			
		||||
    case META_SHAPED_TEXTURE_TYPE_X11_PIXMAP:
 | 
			
		||||
      cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (priv->texture),
 | 
			
		||||
                                           x, y, width, height);
 | 
			
		||||
      break;
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
    case META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE:
 | 
			
		||||
      wayland_surface_update_area (stex, x, y, width, height);
 | 
			
		||||
      break;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
 | 
			
		||||
 | 
			
		||||
  clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_cogl_texture (MetaShapedTexture    *stex,
 | 
			
		||||
                  CoglTexturePixmapX11 *cogl_tex)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
  guint width, height;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->texture != NULL)
 | 
			
		||||
    cogl_object_unref (priv->texture);
 | 
			
		||||
 | 
			
		||||
  priv->texture = cogl_tex;
 | 
			
		||||
 | 
			
		||||
  if (priv->pipeline != NULL)
 | 
			
		||||
    cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
 | 
			
		||||
 | 
			
		||||
  if (priv->pipeline_unshaped != NULL)
 | 
			
		||||
    cogl_pipeline_set_layer_texture (priv->pipeline_unshaped, 0, COGL_TEXTURE (cogl_tex));
 | 
			
		||||
 | 
			
		||||
  if (cogl_tex != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
 | 
			
		||||
      height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
 | 
			
		||||
 | 
			
		||||
      if (width != priv->tex_width ||
 | 
			
		||||
          height != priv->tex_height)
 | 
			
		||||
        {
 | 
			
		||||
          priv->tex_width = width;
 | 
			
		||||
          priv->tex_height = height;
 | 
			
		||||
 | 
			
		||||
          clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* size changed to 0 going to an inavlid texture */
 | 
			
		||||
      priv->tex_width = 0;
 | 
			
		||||
      priv->tex_height = 0;
 | 
			
		||||
      clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
 | 
			
		||||
  queue_damage_redraw_with_clip (stex, x, y, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -501,16 +705,18 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->pixmap == pixmap)
 | 
			
		||||
  if (priv->x11.pixmap == pixmap)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  priv->pixmap = pixmap;
 | 
			
		||||
  priv->x11.pixmap = pixmap;
 | 
			
		||||
 | 
			
		||||
  if (pixmap != None)
 | 
			
		||||
    {
 | 
			
		||||
      CoglContext *ctx =
 | 
			
		||||
        clutter_backend_get_cogl_context (clutter_get_default_backend ());
 | 
			
		||||
      set_cogl_texture (stex, cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
 | 
			
		||||
      CoglTexture *texture =
 | 
			
		||||
        COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
 | 
			
		||||
      set_cogl_texture (stex, texture);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    set_cogl_texture (stex, NULL);
 | 
			
		||||
@@ -520,6 +726,54 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
 | 
			
		||||
                                         COGL_TEXTURE (priv->texture));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
void
 | 
			
		||||
meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture  *stex,
 | 
			
		||||
                                           MetaWaylandBuffer  *buffer)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  /* TODO: we should change this api to be something like
 | 
			
		||||
   * meta_shaped_texture_notify_buffer_attach() since we now maintain
 | 
			
		||||
   * a reference to the MetaWaylandSurface where we can access the
 | 
			
		||||
   * buffer without it being explicitly passed as an argument.
 | 
			
		||||
   */
 | 
			
		||||
  g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
 | 
			
		||||
 | 
			
		||||
  if (buffer)
 | 
			
		||||
    {
 | 
			
		||||
      CoglContext *ctx =
 | 
			
		||||
        clutter_backend_get_cogl_context (clutter_get_default_backend ());
 | 
			
		||||
      CoglError *catch_error = NULL;
 | 
			
		||||
      CoglTexture *texture =
 | 
			
		||||
        COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
 | 
			
		||||
                                                               buffer->resource,
 | 
			
		||||
                                                               &catch_error));
 | 
			
		||||
      if (!texture)
 | 
			
		||||
        {
 | 
			
		||||
          cogl_error_free (catch_error);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          buffer->width = cogl_texture_get_width (texture);
 | 
			
		||||
          buffer->height = cogl_texture_get_height (texture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      set_cogl_texture (stex, texture);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    set_cogl_texture (stex, NULL);
 | 
			
		||||
 | 
			
		||||
  if (priv->create_mipmaps)
 | 
			
		||||
    meta_texture_tower_set_base_texture (priv->paint_tower,
 | 
			
		||||
                                         COGL_TEXTURE (priv->texture));
 | 
			
		||||
}
 | 
			
		||||
#endif /* HAVE_WAYLAND */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_shaped_texture_get_texture:
 | 
			
		||||
 * @stex: The #MetaShapedTexture
 | 
			
		||||
@@ -533,6 +787,41 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex)
 | 
			
		||||
  return COGL_TEXTURE (stex->priv->texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_shaped_texture_set_input_shape_region:
 | 
			
		||||
 * @stex: a #MetaShapedTexture
 | 
			
		||||
 * @shape_region: the region of the texture that should respond to
 | 
			
		||||
 *    input.
 | 
			
		||||
 *
 | 
			
		||||
 * Determines what region of the texture should accept input. For
 | 
			
		||||
 * X based windows this is defined by the ShapeInput region of the
 | 
			
		||||
 * window.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
 | 
			
		||||
                                            cairo_region_t    *shape_region)
 | 
			
		||||
{
 | 
			
		||||
  MetaShapedTexturePrivate *priv;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
 | 
			
		||||
 | 
			
		||||
  priv = stex->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->input_shape_region != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      cairo_region_destroy (priv->input_shape_region);
 | 
			
		||||
      priv->input_shape_region = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (shape_region != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      cairo_region_reference (shape_region);
 | 
			
		||||
      priv->input_shape_region = shape_region;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_shaped_texture_set_clip_region:
 | 
			
		||||
 * @stex: a #MetaShapedTexture
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,11 @@
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include <meta-wayland-private.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <X11/extensions/Xdamage.h>
 | 
			
		||||
#include <meta/compositor-mutter.h>
 | 
			
		||||
 | 
			
		||||
@@ -24,8 +29,20 @@ void meta_window_actor_unmaximize (MetaWindowActor *self,
 | 
			
		||||
                                   MetaRectangle   *old_rect,
 | 
			
		||||
                                   MetaRectangle   *new_rect);
 | 
			
		||||
 | 
			
		||||
void meta_window_actor_process_damage (MetaWindowActor    *self,
 | 
			
		||||
                                       XDamageNotifyEvent *event);
 | 
			
		||||
void meta_window_actor_process_x11_damage (MetaWindowActor    *self,
 | 
			
		||||
                                           XDamageNotifyEvent *event);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
void meta_window_actor_process_wayland_damage (MetaWindowActor *self,
 | 
			
		||||
                                               int              x,
 | 
			
		||||
                                               int              y,
 | 
			
		||||
                                               int              width,
 | 
			
		||||
                                               int              height);
 | 
			
		||||
void meta_window_actor_set_wayland_surface    (MetaWindowActor    *self,
 | 
			
		||||
                                               MetaWaylandSurface *surface);
 | 
			
		||||
void meta_window_actor_attach_wayland_buffer  (MetaWindowActor   *self,
 | 
			
		||||
                                               MetaWaylandBuffer *buffer);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void meta_window_actor_pre_paint      (MetaWindowActor    *self);
 | 
			
		||||
void meta_window_actor_post_paint     (MetaWindowActor    *self);
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,9 @@
 | 
			
		||||
#include "meta-window-actor-private.h"
 | 
			
		||||
#include "meta-texture-rectangle.h"
 | 
			
		||||
#include "region-utils.h"
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  POSITION_CHANGED,
 | 
			
		||||
@@ -64,14 +67,12 @@ struct _MetaWindowActorPrivate
 | 
			
		||||
  MetaShadow       *focused_shadow;
 | 
			
		||||
  MetaShadow       *unfocused_shadow;
 | 
			
		||||
 | 
			
		||||
  Pixmap            back_pixmap;
 | 
			
		||||
 | 
			
		||||
  Damage            damage;
 | 
			
		||||
 | 
			
		||||
  guint8            opacity;
 | 
			
		||||
 | 
			
		||||
  /* A region that matches the shape of the window, including frame bounds */
 | 
			
		||||
  cairo_region_t   *shape_region;
 | 
			
		||||
  /* If the window has an input shape, a region that matches the shape */
 | 
			
		||||
  cairo_region_t   *input_shape_region;
 | 
			
		||||
  /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
 | 
			
		||||
   * the shape region. */
 | 
			
		||||
  cairo_region_t   *opaque_region;
 | 
			
		||||
@@ -102,31 +103,41 @@ struct _MetaWindowActorPrivate
 | 
			
		||||
  /* List of FrameData for recent frames */
 | 
			
		||||
  GList            *frames;
 | 
			
		||||
 | 
			
		||||
  Pixmap            back_pixmap; /* Not used in wayland compositor mode */
 | 
			
		||||
  Damage            damage; /* Not used in wayland compositor mode */
 | 
			
		||||
 | 
			
		||||
  guint		    visible                : 1;
 | 
			
		||||
  guint		    mapped                 : 1;
 | 
			
		||||
  guint		    argb32                 : 1;
 | 
			
		||||
  guint		    disposed               : 1;
 | 
			
		||||
  guint             redecorating           : 1;
 | 
			
		||||
 | 
			
		||||
  guint		    needs_damage_all       : 1;
 | 
			
		||||
  guint		    received_damage        : 1;
 | 
			
		||||
  guint             repaint_scheduled      : 1;
 | 
			
		||||
 | 
			
		||||
  /* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
 | 
			
		||||
   * client message using the most recent frame in ->frames */
 | 
			
		||||
  guint             needs_frame_drawn      : 1;
 | 
			
		||||
  guint             repaint_scheduled      : 1;
 | 
			
		||||
 | 
			
		||||
  guint		    needs_pixmap           : 1;
 | 
			
		||||
  guint             needs_reshape          : 1;
 | 
			
		||||
  guint             recompute_focused_shadow   : 1;
 | 
			
		||||
  guint             recompute_unfocused_shadow : 1;
 | 
			
		||||
  guint		    size_changed           : 1;
 | 
			
		||||
  guint             updates_frozen         : 1;
 | 
			
		||||
 | 
			
		||||
  guint		    needs_destroy	   : 1;
 | 
			
		||||
 | 
			
		||||
  guint             no_shadow              : 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /* 
 | 
			
		||||
   * None of these are used in wayland compositor mode...
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  guint		    needs_damage_all       : 1;
 | 
			
		||||
  guint		    received_x11_damage    : 1;
 | 
			
		||||
 | 
			
		||||
  guint		    needs_pixmap           : 1;
 | 
			
		||||
 | 
			
		||||
  guint		    x11_size_changed       : 1;
 | 
			
		||||
  guint             updates_frozen         : 1;
 | 
			
		||||
 | 
			
		||||
  guint             unredirected           : 1;
 | 
			
		||||
 | 
			
		||||
  /* This is used to detect fullscreen windows that need to be unredirected */
 | 
			
		||||
@@ -170,7 +181,7 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor       *actor,
 | 
			
		||||
                                                    ClutterPaintVolume *volume);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void     meta_window_actor_detach     (MetaWindowActor *self);
 | 
			
		||||
static void meta_window_actor_detach_x11_pixmap     (MetaWindowActor *self);
 | 
			
		||||
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
 | 
			
		||||
 | 
			
		||||
static void meta_window_actor_handle_updates (MetaWindowActor *self);
 | 
			
		||||
@@ -304,18 +315,21 @@ window_decorated_notify (MetaWindow *mw,
 | 
			
		||||
  else
 | 
			
		||||
    new_xwindow = meta_window_get_xwindow (mw);
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_detach (self);
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * First of all, clean up any resources we are currently using and will
 | 
			
		||||
   * be replacing.
 | 
			
		||||
   */
 | 
			
		||||
  if (priv->damage != None)
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      meta_error_trap_push (display);
 | 
			
		||||
      XDamageDestroy (xdisplay, priv->damage);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
      priv->damage = None;
 | 
			
		||||
      meta_window_actor_detach_x11_pixmap (self);
 | 
			
		||||
 | 
			
		||||
      /*
 | 
			
		||||
       * First of all, clean up any resources we are currently using and will
 | 
			
		||||
       * be replacing.
 | 
			
		||||
       */
 | 
			
		||||
      if (priv->damage != None)
 | 
			
		||||
        {
 | 
			
		||||
          meta_error_trap_push (display);
 | 
			
		||||
          XDamageDestroy (xdisplay, priv->damage);
 | 
			
		||||
          meta_error_trap_pop (display);
 | 
			
		||||
          priv->damage = None;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->xwindow = new_xwindow;
 | 
			
		||||
@@ -346,8 +360,9 @@ meta_window_actor_constructed (GObject *object)
 | 
			
		||||
  Display                *xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
  XRenderPictFormat      *format;
 | 
			
		||||
 | 
			
		||||
  priv->damage = XDamageCreate (xdisplay, xwindow,
 | 
			
		||||
                                XDamageReportBoundingBox);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    priv->damage = XDamageCreate (xdisplay, xwindow,
 | 
			
		||||
                                  XDamageReportBoundingBox);
 | 
			
		||||
 | 
			
		||||
  format = XRenderFindVisualFormat (xdisplay, window->xvisual);
 | 
			
		||||
 | 
			
		||||
@@ -356,10 +371,18 @@ meta_window_actor_constructed (GObject *object)
 | 
			
		||||
 | 
			
		||||
  if (!priv->actor)
 | 
			
		||||
    {
 | 
			
		||||
      priv->actor = meta_shaped_texture_new ();
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
      if (meta_is_wayland_compositor ())
 | 
			
		||||
        priv->actor = meta_shaped_texture_new_with_wayland_surface (window->surface);
 | 
			
		||||
      else
 | 
			
		||||
#endif
 | 
			
		||||
        priv->actor = meta_shaped_texture_new_with_xwindow (xwindow);
 | 
			
		||||
 | 
			
		||||
      clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor);
 | 
			
		||||
 | 
			
		||||
      if (meta_is_wayland_compositor ())
 | 
			
		||||
        clutter_actor_set_reactive (priv->actor, TRUE);
 | 
			
		||||
 | 
			
		||||
      /*
 | 
			
		||||
       * Since we are holding a pointer to this actor independently of the
 | 
			
		||||
       * ClutterContainer internals, and provide a public API to access it,
 | 
			
		||||
@@ -385,9 +408,10 @@ meta_window_actor_constructed (GObject *object)
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_update_opacity (self);
 | 
			
		||||
 | 
			
		||||
  /* Start off with an empty region to maintain the invariant that
 | 
			
		||||
     the shape region is always set */
 | 
			
		||||
  /* Start off with empty regions to maintain the invariant that
 | 
			
		||||
     these regions are always set */
 | 
			
		||||
  priv->shape_region = cairo_region_create();
 | 
			
		||||
  priv->input_shape_region = cairo_region_create();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -406,13 +430,18 @@ meta_window_actor_dispose (GObject *object)
 | 
			
		||||
  priv->disposed = TRUE;
 | 
			
		||||
 | 
			
		||||
  screen   = priv->screen;
 | 
			
		||||
  display  = meta_screen_get_display (screen);
 | 
			
		||||
  xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
  info     = meta_screen_get_compositor_data (screen);
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_detach (self);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      display  = meta_screen_get_display (screen);
 | 
			
		||||
      xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
 | 
			
		||||
      meta_window_actor_detach_x11_pixmap (self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&priv->shape_region, cairo_region_destroy);
 | 
			
		||||
  g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
 | 
			
		||||
  g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
 | 
			
		||||
  g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
 | 
			
		||||
 | 
			
		||||
@@ -421,7 +450,7 @@ meta_window_actor_dispose (GObject *object)
 | 
			
		||||
  g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref);
 | 
			
		||||
  g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
 | 
			
		||||
 | 
			
		||||
  if (priv->damage != None)
 | 
			
		||||
  if (!meta_is_wayland_compositor () && priv->damage != None)
 | 
			
		||||
    {
 | 
			
		||||
      meta_error_trap_push (display);
 | 
			
		||||
      XDamageDestroy (xdisplay, priv->damage);
 | 
			
		||||
@@ -893,7 +922,8 @@ meta_window_actor_showing_on_its_workspace (MetaWindowActor *self)
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_freeze (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  self->priv->freeze_count++;
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    self->priv->freeze_count++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -922,30 +952,33 @@ meta_window_actor_damage_all (MetaWindowActor *self)
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_thaw (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  self->priv->freeze_count--;
 | 
			
		||||
 | 
			
		||||
  if (G_UNLIKELY (self->priv->freeze_count < 0))
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Error in freeze/thaw accounting.");
 | 
			
		||||
      self->priv->freeze_count = 0;
 | 
			
		||||
      return;
 | 
			
		||||
      self->priv->freeze_count--;
 | 
			
		||||
 | 
			
		||||
      if (G_UNLIKELY (self->priv->freeze_count < 0))
 | 
			
		||||
        {
 | 
			
		||||
          g_warning ("Error in freeze/thaw accounting.");
 | 
			
		||||
          self->priv->freeze_count = 0;
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (self->priv->freeze_count)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
      /* We sometimes ignore moves and resizes on frozen windows */
 | 
			
		||||
      meta_window_actor_sync_actor_geometry (self, FALSE);
 | 
			
		||||
 | 
			
		||||
      /* We do this now since we might be going right back into the
 | 
			
		||||
       * frozen state */
 | 
			
		||||
      meta_window_actor_handle_updates (self);
 | 
			
		||||
 | 
			
		||||
      /* Since we ignore damage events while a window is frozen for certain effects
 | 
			
		||||
       * we may need to issue an update_area() covering the whole pixmap if we
 | 
			
		||||
       * don't know what real damage has happened. */
 | 
			
		||||
      if (self->priv->needs_damage_all)
 | 
			
		||||
        meta_window_actor_damage_all (self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (self->priv->freeze_count)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* We sometimes ignore moves and resizes on frozen windows */
 | 
			
		||||
  meta_window_actor_sync_actor_geometry (self, FALSE);
 | 
			
		||||
 | 
			
		||||
  /* We do this now since we might be going right back into the
 | 
			
		||||
   * frozen state */
 | 
			
		||||
  meta_window_actor_handle_updates (self);
 | 
			
		||||
 | 
			
		||||
  /* Since we ignore damage events while a window is frozen for certain effects
 | 
			
		||||
   * we may need to issue an update_area() covering the whole pixmap if we
 | 
			
		||||
   * don't know what real damage has happened. */
 | 
			
		||||
  if (self->priv->needs_damage_all)
 | 
			
		||||
    meta_window_actor_damage_all (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -976,7 +1009,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
 | 
			
		||||
       * send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
 | 
			
		||||
       * consistent timing with non-empty frames.
 | 
			
		||||
       */
 | 
			
		||||
      if (priv->mapped && !priv->needs_pixmap)
 | 
			
		||||
      if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
 | 
			
		||||
        {
 | 
			
		||||
          const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
 | 
			
		||||
          clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
 | 
			
		||||
@@ -1002,7 +1035,7 @@ is_frozen (MetaWindowActor *self)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_queue_create_pixmap (MetaWindowActor *self)
 | 
			
		||||
meta_window_actor_queue_create_x11_pixmap (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
@@ -1106,11 +1139,14 @@ meta_window_actor_after_effects (MetaWindowActor *self)
 | 
			
		||||
  meta_window_actor_sync_visibility (self);
 | 
			
		||||
  meta_window_actor_sync_actor_geometry (self, FALSE);
 | 
			
		||||
 | 
			
		||||
  if (!meta_window_is_mapped (priv->window))
 | 
			
		||||
    meta_window_actor_detach (self);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      if (!meta_window_is_mapped (priv->window))
 | 
			
		||||
        meta_window_actor_detach_x11_pixmap (self);
 | 
			
		||||
 | 
			
		||||
  if (priv->needs_pixmap)
 | 
			
		||||
    clutter_actor_queue_redraw (priv->actor);
 | 
			
		||||
      if (priv->needs_pixmap)
 | 
			
		||||
        clutter_actor_queue_redraw (priv->actor);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -1191,7 +1227,7 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
 | 
			
		||||
 * pixmap for a new size.
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_detach (MetaWindowActor *self)
 | 
			
		||||
meta_window_actor_detach_x11_pixmap (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv     = self->priv;
 | 
			
		||||
  MetaScreen            *screen   = priv->screen;
 | 
			
		||||
@@ -1212,7 +1248,7 @@ meta_window_actor_detach (MetaWindowActor *self)
 | 
			
		||||
  XFreePixmap (xdisplay, priv->back_pixmap);
 | 
			
		||||
  priv->back_pixmap = None;
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_queue_create_pixmap (self);
 | 
			
		||||
  meta_window_actor_queue_create_x11_pixmap (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
@@ -1242,7 +1278,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
 | 
			
		||||
  if (meta_window_is_override_redirect (metaWindow))
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  if (priv->does_full_damage)
 | 
			
		||||
  if (!meta_is_wayland_compositor () && priv->does_full_damage)
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
@@ -1262,7 +1298,7 @@ meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
 | 
			
		||||
      meta_error_trap_push (display);
 | 
			
		||||
      XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
      meta_window_actor_detach (self);
 | 
			
		||||
      meta_window_actor_detach_x11_pixmap (self);
 | 
			
		||||
      self->priv->unredirected = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
@@ -1284,6 +1320,11 @@ meta_window_actor_destroy (MetaWindowActor *self)
 | 
			
		||||
 | 
			
		||||
  priv = self->priv;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor), NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  window = priv->window;
 | 
			
		||||
  window_type = meta_window_get_window_type (window);
 | 
			
		||||
  meta_window_set_compositor_private (window, NULL);
 | 
			
		||||
@@ -1335,15 +1376,21 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
 | 
			
		||||
 | 
			
		||||
  meta_window_get_input_rect (priv->window, &window_rect);
 | 
			
		||||
 | 
			
		||||
  if (priv->last_width != window_rect.width ||
 | 
			
		||||
      priv->last_height != window_rect.height)
 | 
			
		||||
  /* When running as a display server then we instead catch size changes when
 | 
			
		||||
   * new buffers are attached */
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      priv->size_changed = TRUE;
 | 
			
		||||
      meta_window_actor_queue_create_pixmap (self);
 | 
			
		||||
      meta_window_actor_update_shape (self);
 | 
			
		||||
      if (priv->last_width != window_rect.width ||
 | 
			
		||||
          priv->last_height != window_rect.height)
 | 
			
		||||
        {
 | 
			
		||||
          priv->x11_size_changed = TRUE;
 | 
			
		||||
          meta_window_actor_queue_create_x11_pixmap (self);
 | 
			
		||||
 | 
			
		||||
      priv->last_width = window_rect.width;
 | 
			
		||||
      priv->last_height = window_rect.height;
 | 
			
		||||
          meta_window_actor_update_shape (self);
 | 
			
		||||
 | 
			
		||||
          priv->last_width = window_rect.width;
 | 
			
		||||
          priv->last_height = window_rect.height;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (meta_window_actor_effect_in_progress (self))
 | 
			
		||||
@@ -1507,16 +1554,27 @@ meta_window_actor_new (MetaWindow *window)
 | 
			
		||||
  MetaWindowActor        *self;
 | 
			
		||||
  MetaWindowActorPrivate *priv;
 | 
			
		||||
  MetaFrame		 *frame;
 | 
			
		||||
  Window		  top_window;
 | 
			
		||||
  Window		  top_window = None;
 | 
			
		||||
  ClutterActor           *window_group;
 | 
			
		||||
 | 
			
		||||
  frame = meta_window_get_frame (window);
 | 
			
		||||
  if (frame)
 | 
			
		||||
    top_window = meta_frame_get_xwindow (frame);
 | 
			
		||||
  else
 | 
			
		||||
    top_window = meta_window_get_xwindow (window);
 | 
			
		||||
  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    {
 | 
			
		||||
      frame = meta_window_get_frame (window);
 | 
			
		||||
      if (frame)
 | 
			
		||||
        top_window = meta_frame_get_xwindow (frame);
 | 
			
		||||
      else
 | 
			
		||||
        top_window = meta_window_get_xwindow (window);
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
 | 
			
		||||
      meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
 | 
			
		||||
    }
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("add window: Meta %p, wayland surface %p\n",
 | 
			
		||||
                    window, window->surface);
 | 
			
		||||
      top_window = None;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  self = g_object_new (META_TYPE_WINDOW_ACTOR,
 | 
			
		||||
                       "meta-window",         window,
 | 
			
		||||
@@ -1526,21 +1584,24 @@ meta_window_actor_new (MetaWindow *window)
 | 
			
		||||
 | 
			
		||||
  priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  priv->last_width = -1;
 | 
			
		||||
  priv->last_height = -1;
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      priv->last_width = -1;
 | 
			
		||||
      priv->last_height = -1;
 | 
			
		||||
 | 
			
		||||
  priv->mapped = meta_window_toplevel_is_mapped (priv->window);
 | 
			
		||||
  if (priv->mapped)
 | 
			
		||||
    meta_window_actor_queue_create_pixmap (self);
 | 
			
		||||
      priv->mapped = meta_window_toplevel_is_mapped (priv->window);
 | 
			
		||||
      if (priv->mapped)
 | 
			
		||||
        meta_window_actor_queue_create_x11_pixmap (self);
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_set_updates_frozen (self,
 | 
			
		||||
                                        meta_window_updates_are_frozen (priv->window));
 | 
			
		||||
      meta_window_actor_set_updates_frozen (self,
 | 
			
		||||
                                            meta_window_updates_are_frozen (priv->window));
 | 
			
		||||
 | 
			
		||||
  /* If a window doesn't start off with updates frozen, we should
 | 
			
		||||
   * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
 | 
			
		||||
   */
 | 
			
		||||
  if (priv->window->extended_sync_request_counter && !priv->updates_frozen)
 | 
			
		||||
    meta_window_actor_queue_frame_drawn (self, FALSE);
 | 
			
		||||
      /* If a window doesn't start off with updates frozen, we should
 | 
			
		||||
       * we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
 | 
			
		||||
       */
 | 
			
		||||
      if (priv->window->extended_sync_request_counter && !priv->updates_frozen)
 | 
			
		||||
        meta_window_actor_queue_frame_drawn (self, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_sync_actor_geometry (self, priv->window->placed);
 | 
			
		||||
 | 
			
		||||
@@ -1575,7 +1636,8 @@ meta_window_actor_mapped (MetaWindowActor *self)
 | 
			
		||||
 | 
			
		||||
  priv->mapped = TRUE;
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_queue_create_pixmap (self);
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    meta_window_actor_queue_create_x11_pixmap (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -1590,8 +1652,11 @@ meta_window_actor_unmapped (MetaWindowActor *self)
 | 
			
		||||
  if (meta_window_actor_effect_in_progress (self))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_window_actor_detach (self);
 | 
			
		||||
  priv->needs_pixmap = FALSE;
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_actor_detach_x11_pixmap (self);
 | 
			
		||||
      priv->needs_pixmap = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1609,10 +1674,21 @@ meta_window_actor_get_obscured_region (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->back_pixmap && priv->opacity == 0xff && !priv->window->shaded)
 | 
			
		||||
    return priv->opaque_region;
 | 
			
		||||
  else
 | 
			
		||||
    return NULL;
 | 
			
		||||
  if (!priv->window->shaded)
 | 
			
		||||
    {
 | 
			
		||||
      if (meta_is_wayland_compositor ())
 | 
			
		||||
        {
 | 
			
		||||
          if (priv->opacity == 0xff)
 | 
			
		||||
            return priv->opaque_region;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          if (priv->back_pixmap && priv->opacity == 0xff)
 | 
			
		||||
            return priv->opaque_region;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
@@ -1725,8 +1801,11 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
 | 
			
		||||
  g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* When running as a wayland compositor we don't make requests for
 | 
			
		||||
 * replacement pixmaps when resizing windows, we will instead be
 | 
			
		||||
 * asked to attach replacement buffers by the clients. */
 | 
			
		||||
static void
 | 
			
		||||
check_needs_pixmap (MetaWindowActor *self)
 | 
			
		||||
check_needs_x11_pixmap (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv     = self->priv;
 | 
			
		||||
  MetaScreen          *screen   = priv->screen;
 | 
			
		||||
@@ -1748,10 +1827,10 @@ check_needs_pixmap (MetaWindowActor *self)
 | 
			
		||||
 | 
			
		||||
  compositor = meta_display_get_compositor (display);
 | 
			
		||||
 | 
			
		||||
  if (priv->size_changed)
 | 
			
		||||
  if (priv->x11_size_changed)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_actor_detach (self);
 | 
			
		||||
      priv->size_changed = FALSE;
 | 
			
		||||
      meta_window_actor_detach_x11_pixmap (self);
 | 
			
		||||
      priv->x11_size_changed = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (display);
 | 
			
		||||
@@ -1883,13 +1962,13 @@ check_needs_shadow (MetaWindowActor *self)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_process_damage (MetaWindowActor    *self,
 | 
			
		||||
                                  XDamageNotifyEvent *event)
 | 
			
		||||
meta_window_actor_process_x11_damage (MetaWindowActor    *self,
 | 
			
		||||
                                      XDamageNotifyEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
 | 
			
		||||
 | 
			
		||||
  priv->received_damage = TRUE;
 | 
			
		||||
  priv->received_x11_damage = TRUE;
 | 
			
		||||
 | 
			
		||||
  if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && !priv->unredirected)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1943,6 +2022,25 @@ meta_window_actor_process_damage (MetaWindowActor    *self,
 | 
			
		||||
  priv->repaint_scheduled = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_process_wayland_damage (MetaWindowActor *self,
 | 
			
		||||
                                          int x,
 | 
			
		||||
                                          int y,
 | 
			
		||||
                                          int width,
 | 
			
		||||
                                          int height)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  if (!priv->mapped)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
 | 
			
		||||
                                   x, y, width, height);
 | 
			
		||||
  priv->repaint_scheduled = TRUE;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_sync_visibility (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
@@ -2082,39 +2180,40 @@ build_and_scan_frame_mask (MetaWindowActor       *self,
 | 
			
		||||
  g_free (mask_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cairo_region_t *
 | 
			
		||||
region_create_from_x_rectangles (const XRectangle *rects,
 | 
			
		||||
                                 int n_rects,
 | 
			
		||||
                                 int dx,
 | 
			
		||||
                                 int dy)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
  cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_rects; i ++)
 | 
			
		||||
    {
 | 
			
		||||
      cairo_rects[i].x = rects[i].x + dx;
 | 
			
		||||
      cairo_rects[i].y = rects[i].y + dy;
 | 
			
		||||
      cairo_rects[i].width = rects[i].width;
 | 
			
		||||
      cairo_rects[i].height = rects[i].height;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return cairo_region_create_rectangles (cairo_rects, n_rects);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
 | 
			
		||||
                                           cairo_rectangle_int_t *client_area)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  MetaScreen *screen = priv->screen;
 | 
			
		||||
  MetaDisplay *display = meta_screen_get_display (screen);
 | 
			
		||||
  MetaFrameBorders borders;
 | 
			
		||||
  cairo_region_t *region = NULL;
 | 
			
		||||
  cairo_rectangle_int_t client_area;
 | 
			
		||||
  gboolean needs_mask;
 | 
			
		||||
 | 
			
		||||
  if (!priv->mapped)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (!priv->needs_reshape)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (priv->shadow_shape != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_shape_unref (priv->shadow_shape);
 | 
			
		||||
      priv->shadow_shape = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_frame_calc_borders (priv->window->frame, &borders);
 | 
			
		||||
 | 
			
		||||
  client_area.x = borders.total.left;
 | 
			
		||||
  client_area.y = borders.total.top;
 | 
			
		||||
  client_area.width = priv->window->rect.width;
 | 
			
		||||
  if (priv->window->shaded)
 | 
			
		||||
    client_area.height = 0;
 | 
			
		||||
  else
 | 
			
		||||
    client_area.height = priv->window->rect.height;
 | 
			
		||||
 | 
			
		||||
  meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
 | 
			
		||||
  g_clear_pointer (&priv->shape_region, cairo_region_destroy);
 | 
			
		||||
  g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
 | 
			
		||||
@@ -2124,6 +2223,8 @@ check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
    {
 | 
			
		||||
      /* Translate the set of XShape rectangles that we
 | 
			
		||||
       * get from the X server to a cairo_region. */
 | 
			
		||||
      MetaScreen *screen = priv->screen;
 | 
			
		||||
      MetaDisplay *display = meta_screen_get_display (screen);
 | 
			
		||||
      Display *xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
      XRectangle *rects;
 | 
			
		||||
      int n_rects, ordering;
 | 
			
		||||
@@ -2138,20 +2239,10 @@ check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
 | 
			
		||||
      if (rects)
 | 
			
		||||
        {
 | 
			
		||||
          int i;
 | 
			
		||||
          cairo_rectangle_int_t *cairo_rects = g_new (cairo_rectangle_int_t, n_rects);
 | 
			
		||||
 | 
			
		||||
          for (i = 0; i < n_rects; i ++)
 | 
			
		||||
            {
 | 
			
		||||
              cairo_rects[i].x = rects[i].x + client_area.x;
 | 
			
		||||
              cairo_rects[i].y = rects[i].y + client_area.y;
 | 
			
		||||
              cairo_rects[i].width = rects[i].width;
 | 
			
		||||
              cairo_rects[i].height = rects[i].height;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          region = region_create_from_x_rectangles (rects, n_rects,
 | 
			
		||||
                                                    client_area->x,
 | 
			
		||||
                                                    client_area->y);
 | 
			
		||||
          XFree (rects);
 | 
			
		||||
          region = cairo_region_create_rectangles (cairo_rects, n_rects);
 | 
			
		||||
          g_free (cairo_rects);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
@@ -2167,14 +2258,14 @@ check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
       * window would have gotten if it was unshaped. In our case,
 | 
			
		||||
       * this is simply the client area.
 | 
			
		||||
       */
 | 
			
		||||
      cairo_region_intersect_rectangle (region, &client_area);
 | 
			
		||||
      cairo_region_intersect_rectangle (region, client_area);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* If we don't have a shape on the server, that means that
 | 
			
		||||
       * we have an implicit shape of one rectangle covering the
 | 
			
		||||
       * entire window. */
 | 
			
		||||
      region = cairo_region_create_rectangle (&client_area);
 | 
			
		||||
      region = cairo_region_create_rectangle (client_area);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* The region at this point should be constrained to the
 | 
			
		||||
@@ -2193,7 +2284,7 @@ check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
       * case, graphical glitches will occur.
 | 
			
		||||
       */
 | 
			
		||||
      priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
 | 
			
		||||
      cairo_region_translate (priv->opaque_region, client_area.x, client_area.y);
 | 
			
		||||
      cairo_region_translate (priv->opaque_region, client_area->x, client_area->y);
 | 
			
		||||
      cairo_region_intersect (priv->opaque_region, region);
 | 
			
		||||
    }
 | 
			
		||||
  else if (priv->argb32)
 | 
			
		||||
@@ -2207,15 +2298,124 @@ check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
       * and scans the mask looking for all opaque pixels,
 | 
			
		||||
       * adding it to region.
 | 
			
		||||
       */
 | 
			
		||||
      build_and_scan_frame_mask (self, &client_area, region);
 | 
			
		||||
      build_and_scan_frame_mask (self, client_area, region);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->shape_region = region;
 | 
			
		||||
 | 
			
		||||
  priv->needs_reshape = FALSE;
 | 
			
		||||
  meta_window_actor_invalidate_shadow (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_update_x11_input_shape_region (MetaWindowActor *self,
 | 
			
		||||
                                                 cairo_rectangle_int_t *client_area)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  cairo_region_t *region = NULL;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SHAPE
 | 
			
		||||
  /* Note: we currently assume that mutter never sets an input region
 | 
			
		||||
   * when there is a frame. */
 | 
			
		||||
  if (priv->window->frame == NULL && priv->window->has_input_shape)
 | 
			
		||||
    {
 | 
			
		||||
      MetaScreen *screen = priv->screen;
 | 
			
		||||
      MetaDisplay *display = meta_screen_get_display (screen);
 | 
			
		||||
      Display *xdisplay = meta_display_get_xdisplay (display);
 | 
			
		||||
      XRectangle *rects;
 | 
			
		||||
      int n_rects, ordering;
 | 
			
		||||
 | 
			
		||||
      /* Note we only actually query the ShapeInput shape of a window
 | 
			
		||||
       * when we don't have a frame because we assume currently that
 | 
			
		||||
       * mutter never sets an ShapeInput shape on a frame. */
 | 
			
		||||
      meta_error_trap_push (display);
 | 
			
		||||
      rects = XShapeGetRectangles (xdisplay,
 | 
			
		||||
                                   priv->window->xwindow,
 | 
			
		||||
                                   ShapeInput,
 | 
			
		||||
                                   &n_rects,
 | 
			
		||||
                                   &ordering);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
      if (rects)
 | 
			
		||||
        {
 | 
			
		||||
          region = region_create_from_x_rectangles (rects, n_rects,
 | 
			
		||||
                                                    client_area->x,
 | 
			
		||||
                                                    client_area->y);
 | 
			
		||||
          XFree (rects);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif /* HAVE_SHAPE */
 | 
			
		||||
 | 
			
		||||
  if (region != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      /* The X shape extension requires us to intersect the input
 | 
			
		||||
       * region with the effective bounding shape to determine the
 | 
			
		||||
       * effective input region.
 | 
			
		||||
       */
 | 
			
		||||
      if (priv->shape_region)
 | 
			
		||||
        cairo_region_intersect (region, priv->shape_region);
 | 
			
		||||
      else
 | 
			
		||||
        cairo_region_intersect_rectangle (region, client_area);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* If we don't have a shape on the server, that means that we
 | 
			
		||||
       * have an implicit shape of one rectangle covering the entire
 | 
			
		||||
       * window. */
 | 
			
		||||
      region = cairo_region_create_rectangle (client_area);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->input_shape_region = region;
 | 
			
		||||
 | 
			
		||||
  meta_shaped_texture_set_input_shape_region (META_SHAPED_TEXTURE (priv->actor),
 | 
			
		||||
                                              priv->input_shape_region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
check_needs_reshape (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  MetaFrameBorders borders;
 | 
			
		||||
  cairo_rectangle_int_t client_area;
 | 
			
		||||
 | 
			
		||||
  if (!priv->mapped)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (!priv->needs_reshape)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_frame_calc_borders (priv->window->frame, &borders);
 | 
			
		||||
 | 
			
		||||
  client_area.x = borders.total.left;
 | 
			
		||||
  client_area.y = borders.total.top;
 | 
			
		||||
  client_area.width = priv->window->rect.width;
 | 
			
		||||
  if (priv->window->shaded)
 | 
			
		||||
    client_area.height = 0;
 | 
			
		||||
  else
 | 
			
		||||
    client_area.height = priv->window->rect.height;
 | 
			
		||||
 | 
			
		||||
  if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_actor_update_x11_shape_region (self, &client_area);
 | 
			
		||||
      meta_window_actor_update_x11_input_shape_region (self, &client_area);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* TODO: properly support setting an input region as specified
 | 
			
		||||
       * via the wayland protocol */
 | 
			
		||||
 | 
			
		||||
      g_clear_pointer (&priv->shape_region, cairo_region_destroy);
 | 
			
		||||
      g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
 | 
			
		||||
      g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
 | 
			
		||||
 | 
			
		||||
      priv->shape_region = cairo_region_create_rectangle (&client_area);
 | 
			
		||||
      priv->opaque_region = cairo_region_reference (priv->shape_region);
 | 
			
		||||
      priv->input_shape_region = cairo_region_reference (priv->shape_region);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->needs_reshape = FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_update_shape (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
@@ -2229,6 +2429,69 @@ meta_window_actor_update_shape (MetaWindowActor *self)
 | 
			
		||||
  clutter_actor_queue_redraw (priv->actor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
static void
 | 
			
		||||
maybe_emit_size_changed (MetaWindowActor *self,
 | 
			
		||||
                         MetaWaylandBuffer *new_buffer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  int                     width = 0, height = 0;
 | 
			
		||||
 | 
			
		||||
  if (new_buffer)
 | 
			
		||||
    {
 | 
			
		||||
      width = new_buffer->width;
 | 
			
		||||
      height = new_buffer->height;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (priv->last_width != width || priv->last_height != height)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_actor_update_shape (self);
 | 
			
		||||
 | 
			
		||||
      /* ::size-changed is supposed to refer to meta_window_get_outer_rect()
 | 
			
		||||
       * but here we are only looking at buffer size changes.
 | 
			
		||||
       *
 | 
			
		||||
       * Emitting it here works pretty much OK because a new buffer size (which
 | 
			
		||||
       * will correspond to the outer rect with the addition of invisible
 | 
			
		||||
       * borders) also normally implies a change to the outer rect. In the rare
 | 
			
		||||
       * case where a change to the window size was exactly balanced by a
 | 
			
		||||
       * change to the invisible borders, we would miss emitting the signal.
 | 
			
		||||
       */
 | 
			
		||||
      g_signal_emit (self, signals[SIZE_CHANGED], 0);
 | 
			
		||||
 | 
			
		||||
      priv->last_width = width;
 | 
			
		||||
      priv->last_height = height;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_set_wayland_surface (MetaWindowActor *self,
 | 
			
		||||
                                       MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor),
 | 
			
		||||
                                           surface);
 | 
			
		||||
  if (surface && surface->buffer_ref.buffer)
 | 
			
		||||
    maybe_emit_size_changed (self, surface->buffer_ref.buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
 | 
			
		||||
                                         MetaWaylandBuffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
  MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
 | 
			
		||||
  CoglTexture *prev_tex = meta_shaped_texture_get_texture (stex);
 | 
			
		||||
 | 
			
		||||
  meta_shaped_texture_attach_wayland_buffer (stex, buffer);
 | 
			
		||||
 | 
			
		||||
  if (!prev_tex)
 | 
			
		||||
    meta_window_actor_sync_actor_geometry (self, FALSE);
 | 
			
		||||
 | 
			
		||||
  maybe_emit_size_changed (self, buffer);
 | 
			
		||||
}
 | 
			
		||||
#endif /* HAVE_WAYLAND */
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_window_actor_handle_updates (MetaWindowActor *self)
 | 
			
		||||
{
 | 
			
		||||
@@ -2244,42 +2507,46 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (priv->unredirected)
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      /* Nothing to do here until/if the window gets redirected again */
 | 
			
		||||
      return;
 | 
			
		||||
      if (priv->unredirected)
 | 
			
		||||
        {
 | 
			
		||||
          /* Nothing to do here until/if the window gets redirected again */
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (priv->received_x11_damage)
 | 
			
		||||
        {
 | 
			
		||||
          meta_error_trap_push (display);
 | 
			
		||||
          XDamageSubtract (xdisplay, priv->damage, None, None);
 | 
			
		||||
          meta_error_trap_pop (display);
 | 
			
		||||
 | 
			
		||||
          /* We need to make sure that any X drawing that happens before the
 | 
			
		||||
           * XDamageSubtract() above is visible to subsequent GL rendering;
 | 
			
		||||
           * the only standardized way to do this is EXT_x11_sync_object,
 | 
			
		||||
           * which isn't yet widely available. For now, we count on details
 | 
			
		||||
           * of Xorg and the open source drivers, and hope for the best
 | 
			
		||||
           * otherwise.
 | 
			
		||||
           *
 | 
			
		||||
           * Xorg and open source driver specifics:
 | 
			
		||||
           *
 | 
			
		||||
           * The X server makes sure to flush drawing to the kernel before
 | 
			
		||||
           * sending out damage events, but since we use DamageReportBoundingBox
 | 
			
		||||
           * there may be drawing between the last damage event and the
 | 
			
		||||
           * XDamageSubtract() that needs to be flushed as well.
 | 
			
		||||
           *
 | 
			
		||||
           * Xorg always makes sure that drawing is flushed to the kernel
 | 
			
		||||
           * before writing events or responses to the client, so any round trip
 | 
			
		||||
           * request at this point is sufficient to flush the GLX buffers.
 | 
			
		||||
           */
 | 
			
		||||
          XSync (xdisplay, False);
 | 
			
		||||
 | 
			
		||||
          priv->received_x11_damage = FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      check_needs_x11_pixmap (self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (priv->received_damage)
 | 
			
		||||
    {
 | 
			
		||||
      meta_error_trap_push (display);
 | 
			
		||||
      XDamageSubtract (xdisplay, priv->damage, None, None);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
 | 
			
		||||
      /* We need to make sure that any X drawing that happens before the
 | 
			
		||||
       * XDamageSubtract() above is visible to subsequent GL rendering;
 | 
			
		||||
       * the only standardized way to do this is EXT_x11_sync_object,
 | 
			
		||||
       * which isn't yet widely available. For now, we count on details
 | 
			
		||||
       * of Xorg and the open source drivers, and hope for the best
 | 
			
		||||
       * otherwise.
 | 
			
		||||
       *
 | 
			
		||||
       * Xorg and open source driver specifics:
 | 
			
		||||
       *
 | 
			
		||||
       * The X server makes sure to flush drawing to the kernel before
 | 
			
		||||
       * sending out damage events, but since we use DamageReportBoundingBox
 | 
			
		||||
       * there may be drawing between the last damage event and the
 | 
			
		||||
       * XDamageSubtract() that needs to be flushed as well.
 | 
			
		||||
       *
 | 
			
		||||
       * Xorg always makes sure that drawing is flushed to the kernel
 | 
			
		||||
       * before writing events or responses to the client, so any round trip
 | 
			
		||||
       * request at this point is sufficient to flush the GLX buffers.
 | 
			
		||||
       */
 | 
			
		||||
      XSync (xdisplay, False);
 | 
			
		||||
 | 
			
		||||
      priv->received_damage = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  check_needs_pixmap (self);
 | 
			
		||||
  check_needs_reshape (self);
 | 
			
		||||
  check_needs_shadow (self);
 | 
			
		||||
}
 | 
			
		||||
@@ -2458,16 +2725,20 @@ void
 | 
			
		||||
meta_window_actor_set_updates_frozen (MetaWindowActor *self,
 | 
			
		||||
                                      gboolean         updates_frozen)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
  updates_frozen = updates_frozen != FALSE;
 | 
			
		||||
 | 
			
		||||
  if (priv->updates_frozen != updates_frozen)
 | 
			
		||||
  /* On wayland we shouldn't need to ever freeze updates... */
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      priv->updates_frozen = updates_frozen;
 | 
			
		||||
      if (updates_frozen)
 | 
			
		||||
        meta_window_actor_freeze (self);
 | 
			
		||||
      else
 | 
			
		||||
        meta_window_actor_thaw (self);
 | 
			
		||||
      MetaWindowActorPrivate *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
      updates_frozen = updates_frozen != FALSE;
 | 
			
		||||
 | 
			
		||||
      if (priv->updates_frozen != updates_frozen)
 | 
			
		||||
        {
 | 
			
		||||
          priv->updates_frozen = updates_frozen;
 | 
			
		||||
          if (updates_frozen)
 | 
			
		||||
            meta_window_actor_freeze (self);
 | 
			
		||||
          else
 | 
			
		||||
            meta_window_actor_thaw (self);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@
 | 
			
		||||
#include "meta-window-group.h"
 | 
			
		||||
#include "meta-background-actor-private.h"
 | 
			
		||||
#include "meta-background-group-private.h"
 | 
			
		||||
#include "window-private.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaWindowGroupClass
 | 
			
		||||
{
 | 
			
		||||
@@ -99,7 +100,7 @@ meta_window_group_paint (ClutterActor *actor)
 | 
			
		||||
  int paint_x_offset, paint_y_offset;
 | 
			
		||||
 | 
			
		||||
  MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
 | 
			
		||||
  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
 | 
			
		||||
  MetaCompScreen *info;
 | 
			
		||||
 | 
			
		||||
  /* Normally we expect an actor to be drawn at it's position on the screen.
 | 
			
		||||
   * However, if we're inside the paint of a ClutterClone, that won't be the
 | 
			
		||||
@@ -136,13 +137,17 @@ meta_window_group_paint (ClutterActor *actor)
 | 
			
		||||
 | 
			
		||||
  visible_region = cairo_region_create_rectangle (&visible_rect);
 | 
			
		||||
 | 
			
		||||
  if (info->unredirected_window != NULL)
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      cairo_rectangle_int_t unredirected_rect;
 | 
			
		||||
      MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
 | 
			
		||||
      info = meta_screen_get_compositor_data (window_group->screen);
 | 
			
		||||
      if (info->unredirected_window != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          cairo_rectangle_int_t unredirected_rect;
 | 
			
		||||
          MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
 | 
			
		||||
 | 
			
		||||
      meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
 | 
			
		||||
      cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
 | 
			
		||||
          meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
 | 
			
		||||
          cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* We walk the list from top to bottom (opposite of painting order),
 | 
			
		||||
@@ -155,7 +160,8 @@ meta_window_group_paint (ClutterActor *actor)
 | 
			
		||||
      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (info->unredirected_window != NULL &&
 | 
			
		||||
      if (!meta_is_wayland_compositor () &&
 | 
			
		||||
          info->unredirected_window != NULL &&
 | 
			
		||||
          child == CLUTTER_ACTOR (info->unredirected_window))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
@@ -180,7 +186,8 @@ meta_window_group_paint (ClutterActor *actor)
 | 
			
		||||
 | 
			
		||||
      if (META_IS_WINDOW_ACTOR (child))
 | 
			
		||||
        {
 | 
			
		||||
          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
 | 
			
		||||
          MetaWindow *meta_window;
 | 
			
		||||
          MetaWindowActor *window_actor = child;
 | 
			
		||||
          int x, y;
 | 
			
		||||
 | 
			
		||||
          if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
 | 
			
		||||
@@ -194,7 +201,14 @@ meta_window_group_paint (ClutterActor *actor)
 | 
			
		||||
 | 
			
		||||
          meta_window_actor_set_visible_region (window_actor, visible_region);
 | 
			
		||||
 | 
			
		||||
          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
 | 
			
		||||
          /* TODO: Track the opaque regions of wayland clients.
 | 
			
		||||
           * Although wayland clients can report opaque window
 | 
			
		||||
           * regions, for now we assume that all wayland clients are
 | 
			
		||||
           * transparent... */
 | 
			
		||||
          meta_window = meta_window_actor_get_meta_window (window_actor);
 | 
			
		||||
 | 
			
		||||
          if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
 | 
			
		||||
              clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
 | 
			
		||||
            {
 | 
			
		||||
              cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
 | 
			
		||||
              if (obscured_region)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,10 @@
 | 
			
		||||
#include <meta/meta-plugin.h>
 | 
			
		||||
#include <meta/window.h>
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
#include <meta/meta-background-group.h>
 | 
			
		||||
#include <meta/meta-background-actor.h>
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <libintl.h>
 | 
			
		||||
#define _(x) dgettext (GETTEXT_PACKAGE, x)
 | 
			
		||||
#define N_(x) x
 | 
			
		||||
@@ -98,6 +101,8 @@ static void kill_window_effects   (MetaPlugin      *plugin,
 | 
			
		||||
                                   MetaWindowActor *actor);
 | 
			
		||||
static void kill_switch_workspace (MetaPlugin      *plugin);
 | 
			
		||||
 | 
			
		||||
static void confirm_display_change (MetaPlugin *plugin);
 | 
			
		||||
 | 
			
		||||
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
 | 
			
		||||
 | 
			
		||||
META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin);
 | 
			
		||||
@@ -113,6 +118,8 @@ struct _MetaDefaultPluginPrivate
 | 
			
		||||
  ClutterActor          *desktop1;
 | 
			
		||||
  ClutterActor          *desktop2;
 | 
			
		||||
 | 
			
		||||
  ClutterActor          *background_group;
 | 
			
		||||
 | 
			
		||||
  MetaPluginInfo         info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -203,6 +210,7 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
 | 
			
		||||
  plugin_class->plugin_info      = plugin_info;
 | 
			
		||||
  plugin_class->kill_window_effects   = kill_window_effects;
 | 
			
		||||
  plugin_class->kill_switch_workspace = kill_switch_workspace;
 | 
			
		||||
  plugin_class->confirm_display_change = confirm_display_change;
 | 
			
		||||
 | 
			
		||||
  g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate));
 | 
			
		||||
}
 | 
			
		||||
@@ -299,9 +307,58 @@ show_stage (MetaPlugin *plugin)
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_monitors_changed (MetaScreen *screen,
 | 
			
		||||
                     MetaPlugin *plugin)
 | 
			
		||||
{
 | 
			
		||||
  MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
 | 
			
		||||
  int i, n;
 | 
			
		||||
 | 
			
		||||
  clutter_actor_destroy_all_children (self->priv->background_group);
 | 
			
		||||
 | 
			
		||||
  n = meta_screen_get_n_monitors (screen);
 | 
			
		||||
  for (i = 0; i < n; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaRectangle rect;
 | 
			
		||||
      ClutterActor *background;
 | 
			
		||||
      ClutterColor color;
 | 
			
		||||
 | 
			
		||||
      meta_screen_get_monitor_geometry (screen, i, &rect);
 | 
			
		||||
 | 
			
		||||
      background = meta_background_actor_new ();
 | 
			
		||||
 | 
			
		||||
      clutter_actor_set_position (background, rect.x, rect.y);
 | 
			
		||||
      clutter_actor_set_size (background, rect.width, rect.height);
 | 
			
		||||
 | 
			
		||||
      /* Don't use rand() here, mesa calls srand() internally when
 | 
			
		||||
         parsing the driconf XML, but it's nice if the colors are
 | 
			
		||||
         reproducible.
 | 
			
		||||
      */
 | 
			
		||||
      clutter_color_init (&color,
 | 
			
		||||
                          g_random_int () % 255,
 | 
			
		||||
                          g_random_int () % 255,
 | 
			
		||||
                          g_random_int () % 255,
 | 
			
		||||
                          255);
 | 
			
		||||
      clutter_actor_set_background_color (background, &color);
 | 
			
		||||
 | 
			
		||||
      clutter_actor_add_child (self->priv->background_group, background);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
start (MetaPlugin *plugin)
 | 
			
		||||
{
 | 
			
		||||
  MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
 | 
			
		||||
  MetaScreen *screen = meta_plugin_get_screen (plugin);
 | 
			
		||||
 | 
			
		||||
  self->priv->background_group = meta_background_group_new ();
 | 
			
		||||
  clutter_actor_insert_child_below (meta_get_window_group_for_screen (screen),
 | 
			
		||||
                                    self->priv->background_group, NULL);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (screen, "monitors-changed",
 | 
			
		||||
                    G_CALLBACK (on_monitors_changed), plugin);
 | 
			
		||||
  on_monitors_changed (screen, plugin);
 | 
			
		||||
 | 
			
		||||
  meta_later_add (META_LATER_BEFORE_REDRAW,
 | 
			
		||||
                  (GSourceFunc) show_stage,
 | 
			
		||||
                  plugin,
 | 
			
		||||
@@ -782,3 +839,33 @@ plugin_info (MetaPlugin *plugin)
 | 
			
		||||
 | 
			
		||||
  return &priv->info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_dialog_closed (GPid     pid,
 | 
			
		||||
                  gint     status,
 | 
			
		||||
                  gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaPlugin *plugin = user_data;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
 | 
			
		||||
  ok = g_spawn_check_exit_status (status, NULL);
 | 
			
		||||
  meta_plugin_complete_display_change (plugin, ok);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
confirm_display_change (MetaPlugin *plugin)
 | 
			
		||||
{
 | 
			
		||||
  GPid pid;
 | 
			
		||||
 | 
			
		||||
  pid = meta_show_dialog ("--question",
 | 
			
		||||
                          "Does the display look OK?",
 | 
			
		||||
                          "20",
 | 
			
		||||
                          NULL,
 | 
			
		||||
                          "_Keep This Configuration",
 | 
			
		||||
                          "_Restore Previous Configuration",
 | 
			
		||||
                          "preferences-desktop-display",
 | 
			
		||||
                          0,
 | 
			
		||||
                          NULL, NULL);
 | 
			
		||||
 | 
			
		||||
  g_child_watch_add (pid, on_dialog_closed, plugin);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -269,6 +269,8 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
  MetaWindow *grab_window;
 | 
			
		||||
  MetaStackWindow stack_window;
 | 
			
		||||
  MetaStackWindow stack_sibling;
 | 
			
		||||
 | 
			
		||||
  display = meta_display_for_x_display (xdisplay);
 | 
			
		||||
  screen = meta_display_screen_for_xwindow (display, xwindow);
 | 
			
		||||
@@ -281,9 +283,13 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
 | 
			
		||||
  changes.sibling = grab_window->frame ? grab_window->frame->xwindow
 | 
			
		||||
                                       : grab_window->xwindow;
 | 
			
		||||
 | 
			
		||||
  stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
  stack_window.x11.xwindow = xwindow;
 | 
			
		||||
  stack_sibling.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
  stack_sibling.x11.xwindow = changes.sibling;
 | 
			
		||||
  meta_stack_tracker_record_lower_below (screen->stack_tracker,
 | 
			
		||||
                                         xwindow,
 | 
			
		||||
                                         changes.sibling,
 | 
			
		||||
                                         &stack_window,
 | 
			
		||||
                                         &stack_sibling,
 | 
			
		||||
                                         XNextRequest (screen->display->xdisplay));
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (display);
 | 
			
		||||
 
 | 
			
		||||
@@ -86,6 +86,14 @@ typedef enum {
 | 
			
		||||
  META_TILE_MAXIMIZED
 | 
			
		||||
} MetaTileMode;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  META_FOCUS_NONE = 0,
 | 
			
		||||
  META_FOCUS_X_CLIENT = 1,
 | 
			
		||||
  META_FOCUS_WAYLAND_CLIENT = 2,
 | 
			
		||||
  META_FOCUS_NO_FOCUS_WINDOW = 3,
 | 
			
		||||
  META_FOCUS_STAGE = 4
 | 
			
		||||
} MetaFocusType;
 | 
			
		||||
 | 
			
		||||
struct _MetaDisplay
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
@@ -117,6 +125,7 @@ struct _MetaDisplay
 | 
			
		||||
   * like the no_focus_window or the stage X window. */
 | 
			
		||||
  Window focus_xwindow;
 | 
			
		||||
  gulong focus_serial;
 | 
			
		||||
  MetaFocusType focus_type;
 | 
			
		||||
 | 
			
		||||
  /* last timestamp passed to XSetInputFocus */
 | 
			
		||||
  guint32 last_focus_time;
 | 
			
		||||
@@ -467,14 +476,18 @@ gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
 | 
			
		||||
/* In above-tab-keycode.c */
 | 
			
		||||
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
 | 
			
		||||
 | 
			
		||||
gboolean meta_display_handle_event (MetaDisplay *display,
 | 
			
		||||
                                    XEvent      *event);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_XI23
 | 
			
		||||
gboolean meta_display_process_barrier_event (MetaDisplay    *display,
 | 
			
		||||
                                             XIBarrierEvent *event);
 | 
			
		||||
#endif /* HAVE_XI23 */
 | 
			
		||||
 | 
			
		||||
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
 | 
			
		||||
                                           MetaScreen  *screen,
 | 
			
		||||
                                           Window       window,
 | 
			
		||||
                                           guint32      timestamp);
 | 
			
		||||
void meta_display_set_input_focus_xwindow (MetaDisplay   *display,
 | 
			
		||||
                                           MetaScreen    *screen,
 | 
			
		||||
                                           MetaFocusType  type,
 | 
			
		||||
                                           Window         window,
 | 
			
		||||
                                           guint32        timestamp);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,7 @@
 | 
			
		||||
#include <X11/Xatom.h>
 | 
			
		||||
#include <X11/cursorfont.h>
 | 
			
		||||
#include "mutter-enum-types.h"
 | 
			
		||||
#include "meta-idle-monitor-private.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RANDR
 | 
			
		||||
#include <X11/extensions/Xrandr.h>
 | 
			
		||||
@@ -517,7 +518,7 @@ meta_display_open (void)
 | 
			
		||||
 | 
			
		||||
  if (meta_is_syncing ())
 | 
			
		||||
    XSynchronize (xdisplay, True);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  g_assert (the_display == NULL);
 | 
			
		||||
  the_display = g_object_new (META_TYPE_DISPLAY, NULL);
 | 
			
		||||
 | 
			
		||||
@@ -931,8 +932,24 @@ meta_display_open (void)
 | 
			
		||||
  while (tmp != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      MetaScreen *screen = tmp->data;
 | 
			
		||||
	
 | 
			
		||||
      meta_screen_manage_all_windows (screen);
 | 
			
		||||
 | 
			
		||||
      if (meta_is_wayland_compositor ())
 | 
			
		||||
        {
 | 
			
		||||
          /* Instead of explicitly enumerating all windows during
 | 
			
		||||
           * initialization, when we run as a wayland compositor we can rely on
 | 
			
		||||
           * xwayland notifying us of all top level windows so we create
 | 
			
		||||
           * MetaWindows when we get those notifications.
 | 
			
		||||
           *
 | 
			
		||||
           * We still want a guard window so we can avoid
 | 
			
		||||
           * unmapping/withdrawing minimized windows for live
 | 
			
		||||
           * thumbnails...
 | 
			
		||||
           */
 | 
			
		||||
          if (screen->guard_window == None)
 | 
			
		||||
            screen->guard_window =
 | 
			
		||||
              meta_screen_create_guard_window (screen->display->xdisplay, screen);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        meta_screen_manage_all_windows (screen);
 | 
			
		||||
 | 
			
		||||
      tmp = tmp->next;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1881,14 +1898,21 @@ get_input_event (MetaDisplay *display,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_focus_window (MetaDisplay *display,
 | 
			
		||||
                     MetaWindow  *window,
 | 
			
		||||
                     Window       xwindow,
 | 
			
		||||
                     gulong       serial)
 | 
			
		||||
update_focus_window (MetaDisplay   *display,
 | 
			
		||||
                     MetaFocusType  type,
 | 
			
		||||
                     MetaWindow    *window,
 | 
			
		||||
                     Window         xwindow,
 | 
			
		||||
                     gulong         serial)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  display->focus_serial = serial;
 | 
			
		||||
 | 
			
		||||
  if (display->focus_xwindow == xwindow)
 | 
			
		||||
  if (display->focus_xwindow == xwindow &&
 | 
			
		||||
      display->focus_type == type &&
 | 
			
		||||
      display->focus_window == window)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (display->focus_window)
 | 
			
		||||
@@ -1910,6 +1934,7 @@ update_focus_window (MetaDisplay *display,
 | 
			
		||||
      meta_window_set_focused_internal (previous, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  display->focus_type = type;
 | 
			
		||||
  display->focus_window = window;
 | 
			
		||||
  display->focus_xwindow = xwindow;
 | 
			
		||||
 | 
			
		||||
@@ -1922,6 +1947,21 @@ update_focus_window (MetaDisplay *display,
 | 
			
		||||
  else
 | 
			
		||||
    meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
 | 
			
		||||
      if (display->focus_type == META_FOCUS_NO_FOCUS_WINDOW ||
 | 
			
		||||
          display->focus_type == META_FOCUS_STAGE)
 | 
			
		||||
        meta_wayland_compositor_set_input_focus (compositor, NULL);
 | 
			
		||||
      else if (window && window->surface)
 | 
			
		||||
        meta_wayland_compositor_set_input_focus (compositor, window);
 | 
			
		||||
      else
 | 
			
		||||
        meta_topic (META_DEBUG_FOCUS, "Focus change has no effect, because there is no matching wayland surface");
 | 
			
		||||
     }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  g_object_notify (G_OBJECT (display), "focus-window");
 | 
			
		||||
  meta_display_update_active_window_hint (display);
 | 
			
		||||
}
 | 
			
		||||
@@ -1956,19 +1996,18 @@ timestamp_too_old (MetaDisplay *display,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
request_xserver_input_focus_change (MetaDisplay *display,
 | 
			
		||||
                                    MetaScreen  *screen,
 | 
			
		||||
                                    Window       xwindow,
 | 
			
		||||
                                    guint32      timestamp)
 | 
			
		||||
request_xserver_input_focus_change (MetaDisplay   *display,
 | 
			
		||||
                                    MetaScreen    *screen,
 | 
			
		||||
                                    MetaFocusType  type,
 | 
			
		||||
                                    MetaWindow    *meta_window,
 | 
			
		||||
                                    Window         xwindow,
 | 
			
		||||
                                    guint32        timestamp)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *meta_window;
 | 
			
		||||
  gulong serial;
 | 
			
		||||
 | 
			
		||||
  if (timestamp_too_old (display, ×tamp))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_window = meta_display_lookup_x_window (display, xwindow);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (display);
 | 
			
		||||
 | 
			
		||||
  /* In order for mutter to know that the focus request succeeded, we track
 | 
			
		||||
@@ -1995,6 +2034,7 @@ request_xserver_input_focus_change (MetaDisplay *display,
 | 
			
		||||
  meta_display_ungrab (display);
 | 
			
		||||
 | 
			
		||||
  update_focus_window (display,
 | 
			
		||||
                       type,
 | 
			
		||||
                       meta_window,
 | 
			
		||||
                       xwindow,
 | 
			
		||||
                       serial);
 | 
			
		||||
@@ -2015,9 +2055,12 @@ handle_window_focus_event (MetaDisplay  *display,
 | 
			
		||||
                           unsigned long serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *focus_window;
 | 
			
		||||
  MetaFocusType type;
 | 
			
		||||
#ifdef WITH_VERBOSE_MODE
 | 
			
		||||
  const char *window_type;
 | 
			
		||||
 | 
			
		||||
  type = META_FOCUS_NONE;
 | 
			
		||||
 | 
			
		||||
  /* Note the event can be on either the window or the frame,
 | 
			
		||||
   * we focus the frame for shaded windows
 | 
			
		||||
   */
 | 
			
		||||
@@ -2029,14 +2072,26 @@ handle_window_focus_event (MetaDisplay  *display,
 | 
			
		||||
        window_type = "frame window";
 | 
			
		||||
      else
 | 
			
		||||
        window_type = "unknown client window";
 | 
			
		||||
 | 
			
		||||
      if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
 | 
			
		||||
        type = META_FOCUS_WAYLAND_CLIENT;
 | 
			
		||||
      else
 | 
			
		||||
        type = META_FOCUS_X_CLIENT;
 | 
			
		||||
    }
 | 
			
		||||
  else if (meta_display_xwindow_is_a_no_focus_window (display, event->event))
 | 
			
		||||
    window_type = "no_focus_window";
 | 
			
		||||
    {
 | 
			
		||||
      window_type = "no_focus_window";
 | 
			
		||||
      type = META_FOCUS_NO_FOCUS_WINDOW;
 | 
			
		||||
    }
 | 
			
		||||
  else if (meta_display_screen_for_root (display, event->event))
 | 
			
		||||
    window_type = "root window";
 | 
			
		||||
  else
 | 
			
		||||
    window_type = "unknown window";
 | 
			
		||||
 | 
			
		||||
  /* Don't change type if we don't know the new window */
 | 
			
		||||
  if (type == META_FOCUS_NONE)
 | 
			
		||||
    type = display->focus_type;
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_FOCUS,
 | 
			
		||||
              "Focus %s event received on %s 0x%lx (%s) "
 | 
			
		||||
              "mode %s detail %s serial %lu\n",
 | 
			
		||||
@@ -2114,6 +2169,7 @@ handle_window_focus_event (MetaDisplay  *display,
 | 
			
		||||
  if (display->server_focus_serial > display->focus_serial)
 | 
			
		||||
    {
 | 
			
		||||
      update_focus_window (display,
 | 
			
		||||
                           type,
 | 
			
		||||
                           focus_window,
 | 
			
		||||
                           focus_window ? focus_window->xwindow : None,
 | 
			
		||||
                           display->server_focus_serial);
 | 
			
		||||
@@ -2121,10 +2177,9 @@ handle_window_focus_event (MetaDisplay  *display,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * event_callback:
 | 
			
		||||
 * meta_display_handle_event:
 | 
			
		||||
 * @display: The MetaDisplay that events are coming from
 | 
			
		||||
 * @event: The event that just happened
 | 
			
		||||
 * @data: The #MetaDisplay that events are coming from, cast to a gpointer
 | 
			
		||||
 *        so that it can be sent to a callback
 | 
			
		||||
 *
 | 
			
		||||
 * This is the most important function in the whole program. It is the heart,
 | 
			
		||||
 * it is the nexus, it is the Grand Central Station of Mutter's world.
 | 
			
		||||
@@ -2134,21 +2189,20 @@ handle_window_focus_event (MetaDisplay  *display,
 | 
			
		||||
 * busy around here. Most of this function is a ginormous switch statement
 | 
			
		||||
 * dealing with all the kinds of events that might turn up.
 | 
			
		||||
 */
 | 
			
		||||
static gboolean
 | 
			
		||||
event_callback (XEvent   *event,
 | 
			
		||||
                gpointer  data)
 | 
			
		||||
gboolean
 | 
			
		||||
meta_display_handle_event (MetaDisplay *display,
 | 
			
		||||
                           XEvent   *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
  MetaWindow *property_for_window;
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  Window modified;
 | 
			
		||||
  gboolean frame_was_receiver;
 | 
			
		||||
  gboolean bypass_compositor;
 | 
			
		||||
  gboolean filter_out_event;
 | 
			
		||||
  XIEvent *input_event;
 | 
			
		||||
  MetaMonitorManager *monitor;
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
  display = data;
 | 
			
		||||
  
 | 
			
		||||
#ifdef WITH_VERBOSE_MODE
 | 
			
		||||
  if (dump_events)
 | 
			
		||||
    meta_spew_event (display, event);
 | 
			
		||||
@@ -2157,6 +2211,14 @@ event_callback (XEvent   *event,
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  sn_display_process_event (display->sn_display, event);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Intercept XRandR events early and don't attempt any
 | 
			
		||||
     processing for them. We still let them through to Gdk though,
 | 
			
		||||
     so it can update its own internal state.
 | 
			
		||||
  */
 | 
			
		||||
  monitor = meta_monitor_manager_get ();
 | 
			
		||||
  if (meta_monitor_manager_handle_xevent (monitor, event))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  
 | 
			
		||||
  bypass_compositor = FALSE;
 | 
			
		||||
  filter_out_event = FALSE;
 | 
			
		||||
@@ -2170,11 +2232,19 @@ event_callback (XEvent   *event,
 | 
			
		||||
      meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n",
 | 
			
		||||
                  display->focus_window->desc);
 | 
			
		||||
      update_focus_window (display,
 | 
			
		||||
                           META_FOCUS_NONE,
 | 
			
		||||
                           meta_display_lookup_x_window (display, display->server_focus_window),
 | 
			
		||||
                           display->server_focus_window,
 | 
			
		||||
                           display->server_focus_serial);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  screen = meta_display_screen_for_root (display, event->xany.window);
 | 
			
		||||
  if (screen)
 | 
			
		||||
    {
 | 
			
		||||
      if (meta_screen_handle_xevent (screen, event))
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  modified = event_get_modified_window (display, event);
 | 
			
		||||
 | 
			
		||||
  input_event = get_input_event (display, event);
 | 
			
		||||
@@ -2247,6 +2317,8 @@ event_callback (XEvent   *event,
 | 
			
		||||
          meta_window_update_sync_request_counter (alarm_window, new_counter_value);
 | 
			
		||||
          filter_out_event = TRUE; /* GTK doesn't want to see this really */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_idle_monitor_handle_xevent_all (event);
 | 
			
		||||
    }
 | 
			
		||||
#endif /* HAVE_XSYNC */
 | 
			
		||||
 | 
			
		||||
@@ -2284,8 +2356,35 @@ event_callback (XEvent   *event,
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              if (display->compositor)
 | 
			
		||||
                meta_compositor_window_shape_changed (display->compositor,
 | 
			
		||||
                                                      window);
 | 
			
		||||
                meta_compositor_window_x11_shape_changed (display->compositor,
 | 
			
		||||
                                                          window);
 | 
			
		||||
            }
 | 
			
		||||
          else if (sev->kind == ShapeInput)
 | 
			
		||||
            {
 | 
			
		||||
              if (sev->shaped && !window->has_input_shape)
 | 
			
		||||
                {
 | 
			
		||||
                  window->has_input_shape = TRUE;                  
 | 
			
		||||
                  meta_topic (META_DEBUG_SHAPES,
 | 
			
		||||
                              "Window %s now has an input shape\n",
 | 
			
		||||
                              window->desc);
 | 
			
		||||
                }
 | 
			
		||||
              else if (!sev->shaped && window->has_input_shape)
 | 
			
		||||
                {
 | 
			
		||||
                  window->has_input_shape = FALSE;
 | 
			
		||||
                  meta_topic (META_DEBUG_SHAPES,
 | 
			
		||||
                              "Window %s no longer has an input shape\n",
 | 
			
		||||
                              window->desc);
 | 
			
		||||
                }
 | 
			
		||||
              else
 | 
			
		||||
                {
 | 
			
		||||
                  meta_topic (META_DEBUG_SHAPES,
 | 
			
		||||
                              "Window %s input shape changed\n",
 | 
			
		||||
                              window->desc);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              if (display->compositor)
 | 
			
		||||
                meta_compositor_window_x11_shape_changed (display->compositor,
 | 
			
		||||
                                                          window);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
@@ -2822,32 +2921,10 @@ event_callback (XEvent   *event,
 | 
			
		||||
                meta_stack_tracker_configure_event (screen->stack_tracker,
 | 
			
		||||
                                                    &event->xconfigure);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (window && window->override_redirect)
 | 
			
		||||
            meta_window_configure_notify (window, &event->xconfigure);
 | 
			
		||||
          else
 | 
			
		||||
            /* Handle screen resize */
 | 
			
		||||
            {
 | 
			
		||||
              MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
              screen = meta_display_screen_for_root (display,
 | 
			
		||||
                                                     event->xconfigure.window);
 | 
			
		||||
 | 
			
		||||
              if (screen != NULL)
 | 
			
		||||
                {
 | 
			
		||||
#ifdef HAVE_RANDR
 | 
			
		||||
                  /* do the resize the official way */
 | 
			
		||||
                  XRRUpdateConfiguration (event);
 | 
			
		||||
#else
 | 
			
		||||
                  /* poke around in Xlib */
 | 
			
		||||
                  screen->xscreen->width   = event->xconfigure.width;
 | 
			
		||||
                  screen->xscreen->height  = event->xconfigure.height;
 | 
			
		||||
#endif
 | 
			
		||||
	      
 | 
			
		||||
                  meta_screen_resize (screen, 
 | 
			
		||||
                                      event->xconfigure.width,
 | 
			
		||||
                                      event->xconfigure.height);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
          break;
 | 
			
		||||
        case ConfigureRequest:
 | 
			
		||||
          /* This comment and code is found in both twm and fvwm */
 | 
			
		||||
@@ -3138,6 +3215,32 @@ event_callback (XEvent   *event,
 | 
			
		||||
  return filter_out_event;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
event_callback (XEvent  *event,
 | 
			
		||||
                gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display = data;
 | 
			
		||||
 | 
			
		||||
  /* Under Wayland we want to filter out mouse motion events so we can
 | 
			
		||||
     synthesize them from the Clutter events instead. This is
 | 
			
		||||
     necessary because the position in the mouse events is passed to
 | 
			
		||||
     the X server relative to the position of the surface. The X
 | 
			
		||||
     server then translates these back to screen coordinates based on
 | 
			
		||||
     the window position. If we rely on this translatation when
 | 
			
		||||
     dragging a window around then the window will jump around
 | 
			
		||||
     erratically because of the lag between updating the window
 | 
			
		||||
     position from the surface position. Instead we bypass the
 | 
			
		||||
     translation altogether by directly using the Clutter events */
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor () &&
 | 
			
		||||
      event->type == GenericEvent &&
 | 
			
		||||
      event->xcookie.evtype == XI_Motion)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return meta_display_handle_event (display, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return the window this has to do with, if any, rather
 | 
			
		||||
 * than the frame or root window that was selecting
 | 
			
		||||
 * for substructure
 | 
			
		||||
@@ -5789,6 +5892,9 @@ meta_display_set_input_focus_window (MetaDisplay *display,
 | 
			
		||||
{
 | 
			
		||||
  request_xserver_input_focus_change (display,
 | 
			
		||||
                                      window->screen,
 | 
			
		||||
                                      window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND ?
 | 
			
		||||
                                      META_FOCUS_WAYLAND_CLIENT : META_FOCUS_X_CLIENT,
 | 
			
		||||
                                      window,
 | 
			
		||||
                                      focus_frame ? window->frame->xwindow : window->xwindow,
 | 
			
		||||
                                      timestamp);
 | 
			
		||||
}
 | 
			
		||||
@@ -5829,13 +5935,16 @@ meta_display_request_take_focus (MetaDisplay *display,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_display_set_input_focus_xwindow (MetaDisplay *display,
 | 
			
		||||
                                      MetaScreen  *screen,
 | 
			
		||||
                                      Window       window,
 | 
			
		||||
                                      guint32      timestamp)
 | 
			
		||||
meta_display_set_input_focus_xwindow (MetaDisplay   *display,
 | 
			
		||||
                                      MetaScreen    *screen,
 | 
			
		||||
                                      MetaFocusType  type,
 | 
			
		||||
                                      Window         window,
 | 
			
		||||
                                      guint32        timestamp)
 | 
			
		||||
{
 | 
			
		||||
  request_xserver_input_focus_change (display,
 | 
			
		||||
                                      screen,
 | 
			
		||||
                                      type,
 | 
			
		||||
                                      NULL,
 | 
			
		||||
                                      window,
 | 
			
		||||
                                      timestamp);
 | 
			
		||||
}
 | 
			
		||||
@@ -5847,6 +5956,8 @@ meta_display_focus_the_no_focus_window (MetaDisplay *display,
 | 
			
		||||
{
 | 
			
		||||
  request_xserver_input_focus_change (display,
 | 
			
		||||
                                      screen,
 | 
			
		||||
                                      META_FOCUS_NO_FOCUS_WINDOW,
 | 
			
		||||
                                      NULL,
 | 
			
		||||
                                      screen->no_focus_window,
 | 
			
		||||
                                      timestamp);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ meta_window_ensure_frame (MetaWindow *window)
 | 
			
		||||
  XSetWindowAttributes attrs;
 | 
			
		||||
  Visual *visual;
 | 
			
		||||
  gulong create_serial;
 | 
			
		||||
  MetaStackWindow stack_window;
 | 
			
		||||
  
 | 
			
		||||
  if (window->frame)
 | 
			
		||||
    return;
 | 
			
		||||
@@ -105,8 +106,10 @@ meta_window_ensure_frame (MetaWindow *window)
 | 
			
		||||
						frame->rect.height,
 | 
			
		||||
						frame->window->screen->number,
 | 
			
		||||
                                                &create_serial);
 | 
			
		||||
  stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
  stack_window.x11.xwindow = frame->xwindow;
 | 
			
		||||
  meta_stack_tracker_record_add (window->screen->stack_tracker,
 | 
			
		||||
                                 frame->xwindow,
 | 
			
		||||
                                 &stack_window,
 | 
			
		||||
                                 create_serial);
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
 | 
			
		||||
@@ -138,8 +141,9 @@ meta_window_ensure_frame (MetaWindow *window)
 | 
			
		||||
  window->rect.x = 0;
 | 
			
		||||
  window->rect.y = 0;
 | 
			
		||||
 | 
			
		||||
  stack_window.x11.xwindow = window->xwindow;
 | 
			
		||||
  meta_stack_tracker_record_remove (window->screen->stack_tracker,
 | 
			
		||||
                                    window->xwindow,
 | 
			
		||||
                                    &stack_window,
 | 
			
		||||
                                    XNextRequest (window->display->xdisplay));
 | 
			
		||||
  XReparentWindow (window->display->xdisplay,
 | 
			
		||||
                   window->xwindow,
 | 
			
		||||
@@ -174,6 +178,7 @@ meta_window_destroy_frame (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaFrame *frame;
 | 
			
		||||
  MetaFrameBorders borders;
 | 
			
		||||
  MetaStackWindow stack_window;
 | 
			
		||||
  
 | 
			
		||||
  if (window->frame == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
@@ -200,8 +205,10 @@ meta_window_destroy_frame (MetaWindow *window)
 | 
			
		||||
                  "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
 | 
			
		||||
      window->unmaps_pending += 1;
 | 
			
		||||
    }
 | 
			
		||||
  stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
  stack_window.x11.xwindow = window->xwindow;
 | 
			
		||||
  meta_stack_tracker_record_add (window->screen->stack_tracker,
 | 
			
		||||
                                 window->xwindow,
 | 
			
		||||
                                 &stack_window,
 | 
			
		||||
                                 XNextRequest (window->display->xdisplay));
 | 
			
		||||
  XReparentWindow (window->display->xdisplay,
 | 
			
		||||
                   window->xwindow,
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,10 @@
 | 
			
		||||
#include <X11/XKBlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
 | 
			
		||||
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
 | 
			
		||||
 | 
			
		||||
@@ -4081,6 +4085,40 @@ handle_set_spew_mark (MetaDisplay    *display,
 | 
			
		||||
  meta_verbose ("-- MARK MARK MARK MARK --\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
static void
 | 
			
		||||
handle_switch_vt (MetaDisplay    *display,
 | 
			
		||||
                  MetaScreen     *screen,
 | 
			
		||||
                  MetaWindow     *window,
 | 
			
		||||
                  XIDeviceEvent  *event,
 | 
			
		||||
                  MetaKeyBinding *binding,
 | 
			
		||||
                  gpointer        dummy)
 | 
			
		||||
{
 | 
			
		||||
    gint vt = binding->handler->data;
 | 
			
		||||
    MetaWaylandCompositor *compositor;
 | 
			
		||||
    MetaTTY *tty;
 | 
			
		||||
 | 
			
		||||
    compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
    tty = meta_wayland_compositor_get_tty (compositor);
 | 
			
		||||
 | 
			
		||||
    if (tty)
 | 
			
		||||
      {
 | 
			
		||||
        GError *error;
 | 
			
		||||
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        if (!meta_tty_activate_vt (tty, vt, &error))
 | 
			
		||||
          {
 | 
			
		||||
            g_warning ("Failed to switch VT: %s", error->message);
 | 
			
		||||
            g_error_free (error);
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
    else
 | 
			
		||||
      {
 | 
			
		||||
        g_debug ("Ignoring VT switch keybinding, not running as VT manager");
 | 
			
		||||
      }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_keybindings_set_custom_handler:
 | 
			
		||||
 * @name: The name of the keybinding to set
 | 
			
		||||
@@ -4405,6 +4443,60 @@ init_builtin_key_bindings (MetaDisplay *display)
 | 
			
		||||
                          META_KEYBINDING_ACTION_SET_SPEW_MARK,
 | 
			
		||||
                          handle_set_spew_mark, 0);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-1",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 1);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-2",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 2);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-3",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 3);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-4",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 4);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-5",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 5);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-6",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 6);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-7",
 | 
			
		||||
                              mutter_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 7);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#undef REVERSES_AND_REVERSED
 | 
			
		||||
 | 
			
		||||
  /************************ PER WINDOW BINDINGS ************************/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								src/core/main.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/core/main.c
									
									
									
									
									
								
							@@ -55,8 +55,12 @@
 | 
			
		||||
#include "session.h"
 | 
			
		||||
#include <meta/prefs.h>
 | 
			
		||||
#include <meta/compositor.h>
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <glib-unix.h>
 | 
			
		||||
#include <gdk/gdkx.h>
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@@ -346,28 +350,41 @@ meta_finalize (void)
 | 
			
		||||
  if (display)
 | 
			
		||||
    meta_display_close (display,
 | 
			
		||||
                        CurrentTime); /* I doubt correct timestamps matter here */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sigterm_pipe_fds[2] = { -1, -1 };
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sigterm_handler (int signum)
 | 
			
		||||
{
 | 
			
		||||
  if (sigterm_pipe_fds[1] >= 0)
 | 
			
		||||
    {
 | 
			
		||||
      int G_GNUC_UNUSED dummy;
 | 
			
		||||
 | 
			
		||||
      dummy = write (sigterm_pipe_fds[1], "", 1);
 | 
			
		||||
      close (sigterm_pipe_fds[1]);
 | 
			
		||||
      sigterm_pipe_fds[1] = -1;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    meta_wayland_finalize ();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
on_sigterm (void)
 | 
			
		||||
on_sigterm (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  meta_quit (META_EXIT_SUCCESS);
 | 
			
		||||
  return FALSE;
 | 
			
		||||
  meta_quit (EXIT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
  return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
crash_handler (int signum)
 | 
			
		||||
{
 | 
			
		||||
  char buffer[256];
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
  MetaTTY *tty;
 | 
			
		||||
 | 
			
		||||
  snprintf (buffer, 256, "Fatal server error: %d\n", signum);
 | 
			
		||||
  write (STDERR_FILENO, buffer, strlen (buffer));
 | 
			
		||||
 | 
			
		||||
  compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  tty = meta_wayland_compositor_get_tty (compositor);
 | 
			
		||||
 | 
			
		||||
  /* Passing FALSE ensures that we only do ioctls, which is
 | 
			
		||||
     safe from a signal handler */
 | 
			
		||||
  if (tty)
 | 
			
		||||
    meta_tty_reset (tty, FALSE);
 | 
			
		||||
 | 
			
		||||
  /* We can't continue with the default handling, so just exit here */
 | 
			
		||||
  _exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -381,7 +398,6 @@ meta_init (void)
 | 
			
		||||
{
 | 
			
		||||
  struct sigaction act;
 | 
			
		||||
  sigset_t empty_mask;
 | 
			
		||||
  GIOChannel *channel;
 | 
			
		||||
  
 | 
			
		||||
  sigemptyset (&empty_mask);
 | 
			
		||||
  act.sa_handler = SIG_IGN;
 | 
			
		||||
@@ -396,20 +412,20 @@ meta_init (void)
 | 
			
		||||
                g_strerror (errno));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (pipe (sigterm_pipe_fds) != 0)
 | 
			
		||||
    g_printerr ("Failed to create SIGTERM pipe: %s\n",
 | 
			
		||||
                g_strerror (errno));
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      act.sa_handler = crash_handler;
 | 
			
		||||
 | 
			
		||||
  channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
 | 
			
		||||
  g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
 | 
			
		||||
  g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL);
 | 
			
		||||
  g_io_channel_set_close_on_unref (channel, TRUE);
 | 
			
		||||
  g_io_channel_unref (channel);
 | 
			
		||||
      /* Ignore if we can't register signal handlers, worse
 | 
			
		||||
         that can happen one needs the sysrq to get out of the VT */
 | 
			
		||||
      sigaction (SIGABRT, &act, NULL);
 | 
			
		||||
      sigaction (SIGSEGV, &act, NULL);
 | 
			
		||||
      sigaction (SIGBUS, &act, NULL);
 | 
			
		||||
      sigaction (SIGFPE, &act, NULL);
 | 
			
		||||
      sigaction (SIGTRAP, &act, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  act.sa_handler = &sigterm_handler;
 | 
			
		||||
  if (sigaction (SIGTERM, &act, NULL) < 0)
 | 
			
		||||
    g_printerr ("Failed to register SIGTERM handler: %s\n",
 | 
			
		||||
		g_strerror (errno));
 | 
			
		||||
  g_unix_signal_add (SIGTERM, on_sigterm, NULL);
 | 
			
		||||
 | 
			
		||||
  if (g_getenv ("MUTTER_VERBOSE"))
 | 
			
		||||
    meta_set_verbose (TRUE);
 | 
			
		||||
@@ -427,9 +443,18 @@ meta_init (void)
 | 
			
		||||
  g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      /* NB: When running as a hybrid wayland compositor we run our own headless X
 | 
			
		||||
       * server so the user can't control the X display to connect too. */
 | 
			
		||||
      meta_wayland_init ();
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
#endif
 | 
			
		||||
    meta_select_display (opt_display_name);
 | 
			
		||||
 | 
			
		||||
  meta_select_display (opt_display_name);
 | 
			
		||||
  meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
 | 
			
		||||
  
 | 
			
		||||
  if (opt_replace_wm)
 | 
			
		||||
    meta_set_replace_current_wm (TRUE);
 | 
			
		||||
@@ -441,10 +466,17 @@ meta_init (void)
 | 
			
		||||
  
 | 
			
		||||
  meta_ui_init ();
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Clutter can only be initialized after the UI.
 | 
			
		||||
   */
 | 
			
		||||
  meta_clutter_init ();
 | 
			
		||||
  /* If we are running with wayland then we don't wait until we have
 | 
			
		||||
   * an X connection before initializing clutter we instead initialize
 | 
			
		||||
   * it earlier since we need to initialize the GL driver so the driver
 | 
			
		||||
   * can register any needed wayland extensions. */
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      /*
 | 
			
		||||
       * Clutter can only be initialized after the UI.
 | 
			
		||||
       */
 | 
			
		||||
      meta_clutter_init ();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								src/core/meta-cursor-tracker-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/core/meta-cursor-tracker-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Giovanni Campagna <gcampagn@redhat.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_CURSOR_TRACKER_PRIVATE_H
 | 
			
		||||
#define META_CURSOR_TRACKER_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <meta/meta-cursor-tracker.h>
 | 
			
		||||
 | 
			
		||||
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
 | 
			
		||||
					    XEvent            *xevent);
 | 
			
		||||
 | 
			
		||||
void     meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
 | 
			
		||||
                                              MetaCursor         cursor);
 | 
			
		||||
void     meta_cursor_tracker_revert_root     (MetaCursorTracker *tracker);
 | 
			
		||||
void     meta_cursor_tracker_set_sprite      (MetaCursorTracker *tracker,
 | 
			
		||||
                                              CoglTexture2D     *texture,
 | 
			
		||||
                                              int                hot_x,
 | 
			
		||||
                                              int                hot_y);
 | 
			
		||||
 | 
			
		||||
void     meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
 | 
			
		||||
					      int                new_x,
 | 
			
		||||
					      int                new_y);
 | 
			
		||||
void     meta_cursor_tracker_paint           (MetaCursorTracker *tracker);
 | 
			
		||||
void     meta_cursor_tracker_queue_redraw    (MetaCursorTracker *tracker,
 | 
			
		||||
					      ClutterActor      *stage);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										451
									
								
								src/core/meta-cursor-tracker.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										451
									
								
								src/core/meta-cursor-tracker.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,451 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Giovanni Campagna <gcampagn@redhat.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:cursor-tracker
 | 
			
		||||
 * @title: MetaCursorTracker
 | 
			
		||||
 * @short_description: Mutter cursor tracking helper
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#include <meta/main.h>
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
#include <meta/errors.h>
 | 
			
		||||
 | 
			
		||||
#include <cogl/cogl.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <X11/extensions/Xfixes.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-cursor-tracker-private.h"
 | 
			
		||||
#include "screen-private.h"
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
 | 
			
		||||
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
 | 
			
		||||
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
 | 
			
		||||
 | 
			
		||||
struct _MetaCursorTracker {
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
  gboolean is_showing;
 | 
			
		||||
 | 
			
		||||
  CoglTexture2D *sprite;
 | 
			
		||||
  int hot_x, hot_y;
 | 
			
		||||
 | 
			
		||||
  CoglTexture2D *root_cursor;
 | 
			
		||||
  int root_hot_x, root_hot_y;
 | 
			
		||||
 | 
			
		||||
  CoglTexture2D *default_cursor;
 | 
			
		||||
 | 
			
		||||
  int current_x, current_y;
 | 
			
		||||
  cairo_rectangle_int_t current_rect;
 | 
			
		||||
  cairo_rectangle_int_t previous_rect;
 | 
			
		||||
  gboolean previous_is_valid;
 | 
			
		||||
 | 
			
		||||
  CoglPipeline *pipeline;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaCursorTrackerClass {
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    CURSOR_CHANGED,
 | 
			
		||||
    LAST_SIGNAL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint signals[LAST_SIGNAL];
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_tracker_init (MetaCursorTracker *self)
 | 
			
		||||
{
 | 
			
		||||
  /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of
 | 
			
		||||
     detecting if the system mouse cursor is showing or not.
 | 
			
		||||
 | 
			
		||||
     On wayland we start with the cursor showing
 | 
			
		||||
  */
 | 
			
		||||
  self->is_showing = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_tracker_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaCursorTracker *self = META_CURSOR_TRACKER (object);
 | 
			
		||||
 | 
			
		||||
  if (self->sprite)
 | 
			
		||||
    cogl_object_unref (self->sprite);
 | 
			
		||||
  if (self->root_cursor)
 | 
			
		||||
    cogl_object_unref (self->root_cursor);
 | 
			
		||||
  if (self->default_cursor)
 | 
			
		||||
    cogl_object_unref (self->default_cursor);
 | 
			
		||||
  if (self->pipeline)
 | 
			
		||||
    cogl_object_unref (self->pipeline);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_cursor_tracker_finalize;
 | 
			
		||||
 | 
			
		||||
  signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed",
 | 
			
		||||
                                          G_TYPE_FROM_CLASS (klass),
 | 
			
		||||
                                          G_SIGNAL_RUN_LAST,
 | 
			
		||||
                                          0,
 | 
			
		||||
                                          NULL, NULL, NULL,
 | 
			
		||||
                                          G_TYPE_NONE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaCursorTracker *
 | 
			
		||||
make_wayland_cursor_tracker (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
  CoglContext *ctx;
 | 
			
		||||
  MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
 | 
			
		||||
  self->screen = screen;
 | 
			
		||||
 | 
			
		||||
  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
 | 
			
		||||
  self->pipeline = cogl_pipeline_new (ctx);
 | 
			
		||||
 | 
			
		||||
  compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  compositor->seat->cursor_tracker = self;
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaCursorTracker *
 | 
			
		||||
make_x11_cursor_tracker (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
 | 
			
		||||
  self->screen = screen;
 | 
			
		||||
 | 
			
		||||
  XFixesSelectCursorInput (screen->display->xdisplay,
 | 
			
		||||
                           screen->xroot,
 | 
			
		||||
                           XFixesDisplayCursorNotifyMask);
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_cursor_tracker_get_for_screen:
 | 
			
		||||
 * @screen: the #MetaScreen
 | 
			
		||||
 *
 | 
			
		||||
 * Retrieves the cursor tracker object for @screen.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none):
 | 
			
		||||
 */
 | 
			
		||||
MetaCursorTracker *
 | 
			
		||||
meta_cursor_tracker_get_for_screen (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaCursorTracker *self;
 | 
			
		||||
 | 
			
		||||
  if (screen->cursor_tracker)
 | 
			
		||||
    return screen->cursor_tracker;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    self = make_wayland_cursor_tracker (screen);
 | 
			
		||||
  else
 | 
			
		||||
    self = make_x11_cursor_tracker (screen);
 | 
			
		||||
 | 
			
		||||
  screen->cursor_tracker = self;
 | 
			
		||||
  return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
 | 
			
		||||
                                   XEvent            *xevent)
 | 
			
		||||
{
 | 
			
		||||
  XFixesCursorNotifyEvent *notify_event;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  notify_event = (XFixesCursorNotifyEvent *)xevent;
 | 
			
		||||
  if (notify_event->subtype != XFixesDisplayCursorNotify)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&tracker->sprite, cogl_object_unref);
 | 
			
		||||
  g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
ensure_xfixes_cursor (MetaCursorTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  XFixesCursorImage *cursor_image;
 | 
			
		||||
  CoglTexture2D *sprite;
 | 
			
		||||
  guint8 *cursor_data;
 | 
			
		||||
  gboolean free_cursor_data;
 | 
			
		||||
  CoglContext *ctx;
 | 
			
		||||
 | 
			
		||||
  if (tracker->sprite)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay);
 | 
			
		||||
  if (!cursor_image)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
 | 
			
		||||
   * quantities as arrays of long; we need to convert on 64 bit */
 | 
			
		||||
  if (sizeof(long) == 4)
 | 
			
		||||
    {
 | 
			
		||||
      cursor_data = (guint8 *)cursor_image->pixels;
 | 
			
		||||
      free_cursor_data = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      int i, j;
 | 
			
		||||
      guint32 *cursor_words;
 | 
			
		||||
      gulong *p;
 | 
			
		||||
      guint32 *q;
 | 
			
		||||
 | 
			
		||||
      cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
 | 
			
		||||
      cursor_data = (guint8 *)cursor_words;
 | 
			
		||||
 | 
			
		||||
      p = cursor_image->pixels;
 | 
			
		||||
      q = cursor_words;
 | 
			
		||||
      for (j = 0; j < cursor_image->height; j++)
 | 
			
		||||
        for (i = 0; i < cursor_image->width; i++)
 | 
			
		||||
          *(q++) = *(p++);
 | 
			
		||||
 | 
			
		||||
      free_cursor_data = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
 | 
			
		||||
  sprite = cogl_texture_2d_new_from_data (ctx,
 | 
			
		||||
                                          cursor_image->width,
 | 
			
		||||
                                          cursor_image->height,
 | 
			
		||||
                                          CLUTTER_CAIRO_FORMAT_ARGB32,
 | 
			
		||||
                                          COGL_PIXEL_FORMAT_ANY,
 | 
			
		||||
                                          cursor_image->width * 4, /* stride */
 | 
			
		||||
                                          cursor_data,
 | 
			
		||||
                                          NULL);
 | 
			
		||||
 | 
			
		||||
  if (free_cursor_data)
 | 
			
		||||
    g_free (cursor_data);
 | 
			
		||||
 | 
			
		||||
  if (sprite != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      tracker->sprite = sprite;
 | 
			
		||||
      tracker->hot_x = cursor_image->xhot;
 | 
			
		||||
      tracker->hot_y = cursor_image->yhot;
 | 
			
		||||
    }
 | 
			
		||||
  XFree (cursor_image);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_cursor_tracker_get_sprite:
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none):
 | 
			
		||||
 */
 | 
			
		||||
CoglTexture *
 | 
			
		||||
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
 | 
			
		||||
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    ensure_xfixes_cursor (tracker);
 | 
			
		||||
 | 
			
		||||
  return COGL_TEXTURE (tracker->sprite);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_cursor_tracker_get_hot:
 | 
			
		||||
 * @tracker:
 | 
			
		||||
 * @x: (out):
 | 
			
		||||
 * @y: (out):
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
 | 
			
		||||
                             int               *x,
 | 
			
		||||
                             int               *y)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
 | 
			
		||||
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    ensure_xfixes_cursor (tracker);
 | 
			
		||||
 | 
			
		||||
  if (x)
 | 
			
		||||
    *x = tracker->hot_x;
 | 
			
		||||
  if (y)
 | 
			
		||||
    *y = tracker->hot_y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
ensure_wayland_cursor (MetaCursorTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  CoglBitmap *bitmap;
 | 
			
		||||
  char *filename;
 | 
			
		||||
 | 
			
		||||
  if (tracker->default_cursor)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  filename = g_build_filename (MUTTER_DATADIR,
 | 
			
		||||
                               "mutter/cursors/left_ptr.png",
 | 
			
		||||
                               NULL);
 | 
			
		||||
 | 
			
		||||
  bitmap = cogl_bitmap_new_from_file (filename, NULL);
 | 
			
		||||
  tracker->default_cursor = cogl_texture_2d_new_from_bitmap (bitmap,
 | 
			
		||||
                                                             COGL_PIXEL_FORMAT_ANY,
 | 
			
		||||
                                                             NULL);
 | 
			
		||||
 | 
			
		||||
  cogl_object_unref (bitmap);
 | 
			
		||||
  g_free (filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
 | 
			
		||||
                                     MetaCursor         cursor)
 | 
			
		||||
{
 | 
			
		||||
  Cursor xcursor;
 | 
			
		||||
  MetaDisplay *display = tracker->screen->display;
 | 
			
		||||
 | 
			
		||||
  /* First create a cursor for X11 applications that don't specify their own */
 | 
			
		||||
  xcursor = meta_display_create_x_cursor (display, cursor);
 | 
			
		||||
 | 
			
		||||
  XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor);
 | 
			
		||||
  XFlush (display->xdisplay);
 | 
			
		||||
  XFreeCursor (display->xdisplay, xcursor);
 | 
			
		||||
 | 
			
		||||
  /* Now update the real root cursor */
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      /* FIXME! We need to load all the other cursors too */
 | 
			
		||||
      ensure_wayland_cursor (tracker);
 | 
			
		||||
 | 
			
		||||
      g_clear_pointer (&tracker->root_cursor, cogl_object_unref);
 | 
			
		||||
      tracker->root_cursor = cogl_object_ref (tracker->default_cursor);
 | 
			
		||||
      tracker->root_hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
 | 
			
		||||
      tracker->root_hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_revert_root (MetaCursorTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  meta_cursor_tracker_set_sprite (tracker,
 | 
			
		||||
                                  tracker->root_cursor,
 | 
			
		||||
                                  tracker->root_hot_x,
 | 
			
		||||
                                  tracker->root_hot_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
 | 
			
		||||
                                CoglTexture2D     *sprite,
 | 
			
		||||
                                int                hot_x,
 | 
			
		||||
                                int                hot_y)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (meta_is_wayland_compositor ());
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&tracker->sprite, cogl_object_unref);
 | 
			
		||||
 | 
			
		||||
  if (sprite)
 | 
			
		||||
    {
 | 
			
		||||
      tracker->sprite = cogl_object_ref (sprite);
 | 
			
		||||
      tracker->hot_x = hot_x;
 | 
			
		||||
      tracker->hot_y = hot_y;
 | 
			
		||||
      cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
 | 
			
		||||
 | 
			
		||||
  meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
 | 
			
		||||
                                     int                new_x,
 | 
			
		||||
                                     int                new_y)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (meta_is_wayland_compositor ());
 | 
			
		||||
 | 
			
		||||
  tracker->current_x = new_x;
 | 
			
		||||
  tracker->current_y = new_y;
 | 
			
		||||
  tracker->current_rect.x = tracker->current_x - tracker->hot_x;
 | 
			
		||||
  tracker->current_rect.y = tracker->current_y - tracker->hot_y;
 | 
			
		||||
 | 
			
		||||
  if (tracker->sprite)
 | 
			
		||||
    {
 | 
			
		||||
      tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite));
 | 
			
		||||
      tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      tracker->current_rect.width = 0;
 | 
			
		||||
      tracker->current_rect.height = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_paint (MetaCursorTracker *tracker)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (meta_is_wayland_compositor ());
 | 
			
		||||
 | 
			
		||||
  if (tracker->sprite == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: try to use a DRM cursor when possible */
 | 
			
		||||
  cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
 | 
			
		||||
                                   tracker->pipeline,
 | 
			
		||||
                                   tracker->current_rect.x,
 | 
			
		||||
                                   tracker->current_rect.y,
 | 
			
		||||
                                   tracker->current_rect.x +
 | 
			
		||||
                                   tracker->current_rect.width,
 | 
			
		||||
                                   tracker->current_rect.y +
 | 
			
		||||
                                   tracker->current_rect.height);
 | 
			
		||||
 | 
			
		||||
  tracker->previous_rect = tracker->current_rect;
 | 
			
		||||
  tracker->previous_is_valid = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
 | 
			
		||||
                                  ClutterActor      *stage)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (meta_is_wayland_compositor ());
 | 
			
		||||
 | 
			
		||||
  if (tracker->previous_is_valid)
 | 
			
		||||
    {
 | 
			
		||||
      clutter_actor_queue_redraw_with_clip (stage, &tracker->previous_rect);
 | 
			
		||||
      tracker->previous_is_valid = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (tracker->sprite == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  clutter_actor_queue_redraw_with_clip (stage, &tracker->current_rect);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								src/core/meta-idle-monitor-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/core/meta-idle-monitor-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
 | 
			
		||||
 *         from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <meta/meta-idle-monitor.h>
 | 
			
		||||
 | 
			
		||||
void meta_idle_monitor_handle_xevent_all (XEvent *xevent);
 | 
			
		||||
 | 
			
		||||
void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor);
 | 
			
		||||
 | 
			
		||||
void meta_idle_monitor_init_dbus (void);
 | 
			
		||||
							
								
								
									
										932
									
								
								src/core/meta-idle-monitor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										932
									
								
								src/core/meta-idle-monitor.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,932 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
 | 
			
		||||
 *         from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:idle-monitor
 | 
			
		||||
 * @title: MetaIdleMonitor
 | 
			
		||||
 * @short_description: Mutter idle counter (similar to X's IDLETIME)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#include <X11/extensions/sync.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
#include <meta/main.h>
 | 
			
		||||
#include <meta/meta-idle-monitor.h>
 | 
			
		||||
#include "display-private.h"
 | 
			
		||||
#include "meta-idle-monitor-private.h"
 | 
			
		||||
#include "meta-dbus-idle-monitor.h"
 | 
			
		||||
 | 
			
		||||
G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
 | 
			
		||||
 | 
			
		||||
struct _MetaIdleMonitor
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
 | 
			
		||||
  GHashTable  *watches;
 | 
			
		||||
  GHashTable  *alarms;
 | 
			
		||||
  int          device_id;
 | 
			
		||||
 | 
			
		||||
  /* X11 implementation */
 | 
			
		||||
  Display     *display;
 | 
			
		||||
  int          sync_event_base;
 | 
			
		||||
  XSyncCounter counter;
 | 
			
		||||
  XSyncAlarm   user_active_alarm;
 | 
			
		||||
 | 
			
		||||
  /* Wayland implementation */
 | 
			
		||||
  guint64      last_event_time;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaIdleMonitorClass
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor          *monitor;
 | 
			
		||||
  guint	                    id;
 | 
			
		||||
  MetaIdleMonitorWatchFunc  callback;
 | 
			
		||||
  gpointer		    user_data;
 | 
			
		||||
  GDestroyNotify            notify;
 | 
			
		||||
  guint64                   timeout_msec;
 | 
			
		||||
 | 
			
		||||
  /* x11 */
 | 
			
		||||
  XSyncAlarm	            xalarm;
 | 
			
		||||
 | 
			
		||||
  /* wayland */
 | 
			
		||||
  GSource                  *timeout_source;
 | 
			
		||||
} MetaIdleMonitorWatch;
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  PROP_0,
 | 
			
		||||
  PROP_DEVICE_ID,
 | 
			
		||||
  PROP_LAST,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GParamSpec *obj_props[PROP_LAST];
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
static MetaIdleMonitor *device_monitors[256];
 | 
			
		||||
static int              device_id_max;
 | 
			
		||||
 | 
			
		||||
static gint64
 | 
			
		||||
_xsyncvalue_to_int64 (XSyncValue value)
 | 
			
		||||
{
 | 
			
		||||
  return ((guint64) XSyncValueHigh32 (value)) << 32
 | 
			
		||||
    | (guint64) XSyncValueLow32 (value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, value, ((guint64)value) >> 32)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fire_watch (MetaIdleMonitorWatch *watch)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor *monitor;
 | 
			
		||||
 | 
			
		||||
  monitor = watch->monitor;
 | 
			
		||||
  g_object_ref (monitor);
 | 
			
		||||
 | 
			
		||||
  if (watch->callback)
 | 
			
		||||
    {
 | 
			
		||||
      watch->callback (watch->monitor,
 | 
			
		||||
                       watch->id,
 | 
			
		||||
                       watch->user_data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (watch->timeout_msec == 0)
 | 
			
		||||
    meta_idle_monitor_remove_watch (watch->monitor, watch->id);
 | 
			
		||||
 | 
			
		||||
  g_object_unref (monitor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static XSyncAlarm
 | 
			
		||||
_xsync_alarm_set (MetaIdleMonitor	*monitor,
 | 
			
		||||
		  XSyncTestType          test_type,
 | 
			
		||||
		  guint64                interval,
 | 
			
		||||
		  gboolean               want_events)
 | 
			
		||||
{
 | 
			
		||||
  XSyncAlarmAttributes attr;
 | 
			
		||||
  XSyncValue	     delta;
 | 
			
		||||
  guint		     flags;
 | 
			
		||||
 | 
			
		||||
  flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
 | 
			
		||||
    XSyncCAValue | XSyncCADelta | XSyncCAEvents;
 | 
			
		||||
 | 
			
		||||
  XSyncIntToValue (&delta, 0);
 | 
			
		||||
  attr.trigger.counter = monitor->counter;
 | 
			
		||||
  attr.trigger.value_type = XSyncAbsolute;
 | 
			
		||||
  attr.delta = delta;
 | 
			
		||||
  attr.events = want_events;
 | 
			
		||||
 | 
			
		||||
  GINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
 | 
			
		||||
  attr.trigger.test_type = test_type;
 | 
			
		||||
  return XSyncCreateAlarm (monitor->display, flags, &attr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
ensure_alarm_rescheduled (Display    *dpy,
 | 
			
		||||
			  XSyncAlarm  alarm)
 | 
			
		||||
{
 | 
			
		||||
  XSyncAlarmAttributes attr;
 | 
			
		||||
 | 
			
		||||
  /* Some versions of Xorg have an issue where alarms aren't
 | 
			
		||||
   * always rescheduled. Calling XSyncChangeAlarm, even
 | 
			
		||||
   * without any attributes, will reschedule the alarm. */
 | 
			
		||||
  XSyncChangeAlarm (dpy, alarm, 0, &attr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_alarm_enabled (Display    *dpy,
 | 
			
		||||
		   XSyncAlarm  alarm,
 | 
			
		||||
		   gboolean    enabled)
 | 
			
		||||
{
 | 
			
		||||
  XSyncAlarmAttributes attr;
 | 
			
		||||
  attr.events = enabled;
 | 
			
		||||
  XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
check_x11_watch (gpointer data,
 | 
			
		||||
                 gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatch *watch = data;
 | 
			
		||||
  XSyncAlarm alarm = (XSyncAlarm) user_data;
 | 
			
		||||
 | 
			
		||||
  if (watch->xalarm != alarm)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  fire_watch (watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_handle_xevent (MetaIdleMonitor       *monitor,
 | 
			
		||||
                                 XSyncAlarmNotifyEvent *alarm_event)
 | 
			
		||||
{
 | 
			
		||||
  XSyncAlarm alarm;
 | 
			
		||||
  GList *watches;
 | 
			
		||||
  gboolean has_alarm;
 | 
			
		||||
 | 
			
		||||
  if (alarm_event->state != XSyncAlarmActive)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  alarm = alarm_event->alarm;
 | 
			
		||||
 | 
			
		||||
  has_alarm = FALSE;
 | 
			
		||||
 | 
			
		||||
  if (alarm == monitor->user_active_alarm)
 | 
			
		||||
    {
 | 
			
		||||
      set_alarm_enabled (monitor->display,
 | 
			
		||||
                         alarm,
 | 
			
		||||
                         FALSE);
 | 
			
		||||
      has_alarm = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm))
 | 
			
		||||
    {
 | 
			
		||||
      ensure_alarm_rescheduled (monitor->display,
 | 
			
		||||
                                alarm);
 | 
			
		||||
      has_alarm = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (has_alarm)
 | 
			
		||||
    {
 | 
			
		||||
      watches = g_hash_table_get_values (monitor->watches);
 | 
			
		||||
 | 
			
		||||
      g_list_foreach (watches, check_x11_watch, monitor);
 | 
			
		||||
      g_list_free (watches);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_idle_monitor_handle_xevent_all (XEvent *xevent)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < device_id_max; i++)
 | 
			
		||||
    if (device_monitors[i])
 | 
			
		||||
      meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
counter_name_for_device (int device_id)
 | 
			
		||||
{
 | 
			
		||||
  if (device_id > 0)
 | 
			
		||||
    return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
 | 
			
		||||
 | 
			
		||||
  return g_strdup ("IDLETIME");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static XSyncCounter
 | 
			
		||||
find_idletime_counter (MetaIdleMonitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
  int		      i;
 | 
			
		||||
  int		      ncounters;
 | 
			
		||||
  XSyncSystemCounter *counters;
 | 
			
		||||
  XSyncCounter        counter = None;
 | 
			
		||||
  char               *counter_name;
 | 
			
		||||
 | 
			
		||||
  counter_name = counter_name_for_device (monitor->device_id);
 | 
			
		||||
  counters = XSyncListSystemCounters (monitor->display, &ncounters);
 | 
			
		||||
  for (i = 0; i < ncounters; i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0)
 | 
			
		||||
        {
 | 
			
		||||
          counter = counters[i].counter;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  XSyncFreeSystemCounterList (counters);
 | 
			
		||||
  g_free (counter_name);
 | 
			
		||||
 | 
			
		||||
  return counter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static guint32
 | 
			
		||||
get_next_watch_serial (void)
 | 
			
		||||
{
 | 
			
		||||
  static guint32 serial = 0;
 | 
			
		||||
  g_atomic_int_inc (&serial);
 | 
			
		||||
  return serial;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
idle_monitor_watch_free (MetaIdleMonitorWatch *watch)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor *monitor;
 | 
			
		||||
 | 
			
		||||
  if (watch == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  monitor = watch->monitor;
 | 
			
		||||
 | 
			
		||||
  if (watch->notify != NULL)
 | 
			
		||||
    watch->notify (watch->user_data);
 | 
			
		||||
 | 
			
		||||
  if (watch->xalarm != monitor->user_active_alarm &&
 | 
			
		||||
      watch->xalarm != None)
 | 
			
		||||
    {
 | 
			
		||||
      XSyncDestroyAlarm (monitor->display, watch->xalarm);
 | 
			
		||||
      g_hash_table_remove (monitor->alarms, (gpointer) watch->xalarm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (watch->timeout_source != NULL)
 | 
			
		||||
    g_source_destroy (watch->timeout_source);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (MetaIdleMonitorWatch, watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_xsync (MetaIdleMonitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
  monitor->counter = find_idletime_counter (monitor);
 | 
			
		||||
  /* IDLETIME counter not found? */
 | 
			
		||||
  if (monitor->counter == None)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor *monitor;
 | 
			
		||||
 | 
			
		||||
  monitor = META_IDLE_MONITOR (object);
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&monitor->watches, g_hash_table_destroy);
 | 
			
		||||
  g_clear_pointer (&monitor->alarms, g_hash_table_destroy);
 | 
			
		||||
 | 
			
		||||
  if (monitor->user_active_alarm != None)
 | 
			
		||||
    {
 | 
			
		||||
      XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm);
 | 
			
		||||
      monitor->user_active_alarm = None;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_get_property (GObject    *object,
 | 
			
		||||
                                guint       prop_id,
 | 
			
		||||
                                GValue     *value,
 | 
			
		||||
                                GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_DEVICE_ID:
 | 
			
		||||
      g_value_set_int (value, monitor->device_id);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_set_property (GObject      *object,
 | 
			
		||||
                                guint         prop_id,
 | 
			
		||||
                                const GValue *value,
 | 
			
		||||
                                GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_DEVICE_ID:
 | 
			
		||||
      monitor->device_id = g_value_get_int (value);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_constructed (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
 | 
			
		||||
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      monitor->display = meta_get_display ()->xdisplay;
 | 
			
		||||
      init_xsync (monitor);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->dispose = meta_idle_monitor_dispose;
 | 
			
		||||
  object_class->constructed = meta_idle_monitor_constructed;
 | 
			
		||||
  object_class->get_property = meta_idle_monitor_get_property;
 | 
			
		||||
  object_class->set_property = meta_idle_monitor_set_property;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * MetaIdleMonitor:device_id:
 | 
			
		||||
   *
 | 
			
		||||
   * The device to listen to idletime on.
 | 
			
		||||
   */
 | 
			
		||||
  obj_props[PROP_DEVICE_ID] =
 | 
			
		||||
    g_param_spec_int ("device-id",
 | 
			
		||||
                      "Device ID",
 | 
			
		||||
                      "The device to listen to idletime on",
 | 
			
		||||
                      0, 255, 0,
 | 
			
		||||
                      G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
 | 
			
		||||
  g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_idle_monitor_init (MetaIdleMonitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
  monitor->watches = g_hash_table_new_full (NULL,
 | 
			
		||||
                                                  NULL,
 | 
			
		||||
                                                  NULL,
 | 
			
		||||
                                                  (GDestroyNotify)idle_monitor_watch_free);
 | 
			
		||||
 | 
			
		||||
  monitor->alarms = g_hash_table_new (NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
ensure_device_monitor (int device_id)
 | 
			
		||||
{
 | 
			
		||||
  if (device_monitors[device_id])
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL);
 | 
			
		||||
  device_id_max = MAX (device_id_max, device_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_idle_monitor_get_core:
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global
 | 
			
		||||
 * idletime for all devices. To track device-specific idletime,
 | 
			
		||||
 * use meta_idle_monitor_get_for_device().
 | 
			
		||||
 */
 | 
			
		||||
MetaIdleMonitor *
 | 
			
		||||
meta_idle_monitor_get_core (void)
 | 
			
		||||
{
 | 
			
		||||
  ensure_device_monitor (0);
 | 
			
		||||
  return device_monitors[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_idle_monitor_get_for_device:
 | 
			
		||||
 * @device_id: the device to get the idle time for.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (transfer none): a new #MetaIdleMonitor that tracks the
 | 
			
		||||
 * device-specific idletime for @device. To track server-global idletime
 | 
			
		||||
 * for all devices, use meta_idle_monitor_get_core().
 | 
			
		||||
 */
 | 
			
		||||
MetaIdleMonitor *
 | 
			
		||||
meta_idle_monitor_get_for_device (int device_id)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (device_id > 0 && device_id < 256, NULL);
 | 
			
		||||
 | 
			
		||||
  ensure_device_monitor (device_id);
 | 
			
		||||
  return device_monitors[device_id];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
wayland_dispatch_timeout (GSource     *source,
 | 
			
		||||
                          GSourceFunc  callback,
 | 
			
		||||
                          gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatch *watch = user_data;
 | 
			
		||||
 | 
			
		||||
  fire_watch (watch);
 | 
			
		||||
  g_source_set_ready_time (watch->timeout_source, -1);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GSourceFuncs wayland_source_funcs = {
 | 
			
		||||
  NULL, /* prepare */
 | 
			
		||||
  NULL, /* check */
 | 
			
		||||
  wayland_dispatch_timeout,
 | 
			
		||||
  NULL, /* finalize */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static MetaIdleMonitorWatch *
 | 
			
		||||
make_watch (MetaIdleMonitor           *monitor,
 | 
			
		||||
            guint64                    timeout_msec,
 | 
			
		||||
	    MetaIdleMonitorWatchFunc   callback,
 | 
			
		||||
	    gpointer                   user_data,
 | 
			
		||||
	    GDestroyNotify             notify)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatch *watch;
 | 
			
		||||
 | 
			
		||||
  watch = g_slice_new0 (MetaIdleMonitorWatch);
 | 
			
		||||
  watch->monitor = monitor;
 | 
			
		||||
  watch->id = get_next_watch_serial ();
 | 
			
		||||
  watch->callback = callback;
 | 
			
		||||
  watch->user_data = user_data;
 | 
			
		||||
  watch->notify = notify;
 | 
			
		||||
  watch->timeout_msec = timeout_msec;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      if (timeout_msec != 0)
 | 
			
		||||
        {
 | 
			
		||||
          GSource *source = g_source_new (&wayland_source_funcs, sizeof (GSource));
 | 
			
		||||
 | 
			
		||||
          g_source_set_callback (source, NULL, watch, NULL);
 | 
			
		||||
          g_source_set_ready_time (source, monitor->last_event_time + timeout_msec * 1000);
 | 
			
		||||
          g_source_attach (source, NULL);
 | 
			
		||||
          g_source_unref (source);
 | 
			
		||||
 | 
			
		||||
          watch->timeout_source = source;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (timeout_msec != 0)
 | 
			
		||||
        {
 | 
			
		||||
          watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE);
 | 
			
		||||
 | 
			
		||||
          g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          watch->xalarm = monitor->user_active_alarm;
 | 
			
		||||
 | 
			
		||||
          set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_hash_table_insert (monitor->watches,
 | 
			
		||||
                       GUINT_TO_POINTER (watch->id),
 | 
			
		||||
                       watch);
 | 
			
		||||
  return watch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_idle_monitor_add_idle_watch:
 | 
			
		||||
 * @monitor: A #MetaIdleMonitor
 | 
			
		||||
 * @interval_msec: The idletime interval, in milliseconds
 | 
			
		||||
 * @callback: (allow-none): The callback to call when the user has
 | 
			
		||||
 *     accumulated @interval_msec milliseconds of idle time.
 | 
			
		||||
 * @user_data: (allow-none): The user data to pass to the callback
 | 
			
		||||
 * @notify: A #GDestroyNotify
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: a watch id
 | 
			
		||||
 *
 | 
			
		||||
 * Adds a watch for a specific idle time. The callback will be called
 | 
			
		||||
 * when the user has accumulated @interval_msec milliseconds of idle time.
 | 
			
		||||
 * This function will return an ID that can either be passed to
 | 
			
		||||
 * meta_idle_monitor_remove_watch(), or can be used to tell idle time
 | 
			
		||||
 * watches apart if you have more than one.
 | 
			
		||||
 *
 | 
			
		||||
 * Also note that this function will only care about positive transitions
 | 
			
		||||
 * (user's idle time exceeding a certain time). If you want to know about
 | 
			
		||||
 * when the user has become active, use
 | 
			
		||||
 * meta_idle_monitor_add_user_active_watch().
 | 
			
		||||
 */
 | 
			
		||||
guint
 | 
			
		||||
meta_idle_monitor_add_idle_watch (MetaIdleMonitor	       *monitor,
 | 
			
		||||
                                  guint64	                interval_msec,
 | 
			
		||||
                                  MetaIdleMonitorWatchFunc      callback,
 | 
			
		||||
                                  gpointer			user_data,
 | 
			
		||||
                                  GDestroyNotify		notify)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatch *watch;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
 | 
			
		||||
  g_return_val_if_fail (interval_msec > 0, 0);
 | 
			
		||||
 | 
			
		||||
  watch = make_watch (monitor,
 | 
			
		||||
                      interval_msec,
 | 
			
		||||
                      callback,
 | 
			
		||||
                      user_data,
 | 
			
		||||
                      notify);
 | 
			
		||||
 | 
			
		||||
  return watch->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_idle_monitor_add_user_active_watch:
 | 
			
		||||
 * @monitor: A #MetaIdleMonitor
 | 
			
		||||
 * @callback: (allow-none): The callback to call when the user is
 | 
			
		||||
 *     active again.
 | 
			
		||||
 * @user_data: (allow-none): The user data to pass to the callback
 | 
			
		||||
 * @notify: A #GDestroyNotify
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: a watch id
 | 
			
		||||
 *
 | 
			
		||||
 * Add a one-time watch to know when the user is active again.
 | 
			
		||||
 * Note that this watch is one-time and will de-activate after the
 | 
			
		||||
 * function is called, for efficiency purposes. It's most convenient
 | 
			
		||||
 * to call this when an idle watch, as added by
 | 
			
		||||
 * meta_idle_monitor_add_idle_watch(), has triggered.
 | 
			
		||||
 */
 | 
			
		||||
guint
 | 
			
		||||
meta_idle_monitor_add_user_active_watch (MetaIdleMonitor          *monitor,
 | 
			
		||||
                                         MetaIdleMonitorWatchFunc  callback,
 | 
			
		||||
                                         gpointer		   user_data,
 | 
			
		||||
                                         GDestroyNotify	           notify)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatch *watch;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
 | 
			
		||||
 | 
			
		||||
  watch = make_watch (monitor,
 | 
			
		||||
                      0,
 | 
			
		||||
                      callback,
 | 
			
		||||
                      user_data,
 | 
			
		||||
                      notify);
 | 
			
		||||
 | 
			
		||||
  return watch->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_idle_monitor_remove_watch:
 | 
			
		||||
 * @monitor: A #MetaIdleMonitor
 | 
			
		||||
 * @id: A watch ID
 | 
			
		||||
 *
 | 
			
		||||
 * Removes an idle time watcher, previously added by
 | 
			
		||||
 * meta_idle_monitor_add_idle_watch() or
 | 
			
		||||
 * meta_idle_monitor_add_user_active_watch().
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
 | 
			
		||||
                                guint	         id)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (META_IS_IDLE_MONITOR (monitor));
 | 
			
		||||
 | 
			
		||||
  g_hash_table_remove (monitor->watches,
 | 
			
		||||
                       GUINT_TO_POINTER (id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_idle_monitor_get_idletime:
 | 
			
		||||
 * @monitor: A #MetaIdleMonitor
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: The current idle time, in milliseconds, or -1 for not supported
 | 
			
		||||
 */
 | 
			
		||||
guint64
 | 
			
		||||
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
  XSyncValue value;
 | 
			
		||||
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      return (g_get_monotonic_time () - monitor->last_event_time) / 1000;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (!XSyncQueryCounter (monitor->display, monitor->counter, &value))
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
      return _xsyncvalue_to_int64 (value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  MetaIdleMonitor *monitor;
 | 
			
		||||
  GList *fired_watches;
 | 
			
		||||
} CheckWaylandClosure;
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
check_wayland_watch (gpointer key,
 | 
			
		||||
                     gpointer value,
 | 
			
		||||
                     gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatch *watch = value;
 | 
			
		||||
  CheckWaylandClosure *closure = user_data;
 | 
			
		||||
  gboolean steal;
 | 
			
		||||
 | 
			
		||||
  if (watch->timeout_msec == 0)
 | 
			
		||||
    {
 | 
			
		||||
      closure->fired_watches = g_list_prepend (closure->fired_watches, watch);
 | 
			
		||||
      steal = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_source_set_ready_time (watch->timeout_source,
 | 
			
		||||
                               closure->monitor->last_event_time +
 | 
			
		||||
                               watch->timeout_msec * 1000);
 | 
			
		||||
      steal = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return steal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fire_wayland_watch (gpointer watch,
 | 
			
		||||
                    gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  fire_watch (watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
  CheckWaylandClosure closure;
 | 
			
		||||
 | 
			
		||||
  monitor->last_event_time = g_get_monotonic_time ();
 | 
			
		||||
 | 
			
		||||
  closure.monitor = monitor;
 | 
			
		||||
  closure.fired_watches = NULL;
 | 
			
		||||
  g_hash_table_foreach_steal (monitor->watches, check_wayland_watch, &closure);
 | 
			
		||||
 | 
			
		||||
  g_list_foreach (closure.fired_watches, fire_wayland_watch, NULL);
 | 
			
		||||
  g_list_free (closure.fired_watches);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
handle_get_idletime (MetaDBusIdleMonitor   *skeleton,
 | 
			
		||||
                     GDBusMethodInvocation *invocation,
 | 
			
		||||
                     MetaIdleMonitor       *monitor)
 | 
			
		||||
{
 | 
			
		||||
  guint64 idletime;
 | 
			
		||||
 | 
			
		||||
  idletime = meta_idle_monitor_get_idletime (monitor);
 | 
			
		||||
  meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  MetaDBusIdleMonitor *dbus_monitor;
 | 
			
		||||
  MetaIdleMonitor *monitor;
 | 
			
		||||
  char *dbus_name;
 | 
			
		||||
  guint watch_id;
 | 
			
		||||
  guint name_watcher_id;
 | 
			
		||||
} DBusWatch;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_dbus_watch (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  DBusWatch *watch = data;
 | 
			
		||||
 | 
			
		||||
  g_object_unref (watch->dbus_monitor);
 | 
			
		||||
  g_object_unref (watch->monitor);
 | 
			
		||||
  g_free (watch->dbus_name);
 | 
			
		||||
  g_bus_unwatch_name (watch->name_watcher_id);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (DBusWatch, watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
dbus_idle_callback (MetaIdleMonitor *monitor,
 | 
			
		||||
                    guint            watch_id,
 | 
			
		||||
                    gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  DBusWatch *watch = user_data;
 | 
			
		||||
  GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor);
 | 
			
		||||
 | 
			
		||||
  g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton),
 | 
			
		||||
                                 watch->dbus_name,
 | 
			
		||||
                                 g_dbus_interface_skeleton_get_object_path (skeleton),
 | 
			
		||||
                                 "org.gnome.Mutter.IdleMonitor",
 | 
			
		||||
                                 "WatchFired",
 | 
			
		||||
                                 g_variant_new ("(u)", watch_id),
 | 
			
		||||
                                 NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
name_vanished_callback (GDBusConnection *connection,
 | 
			
		||||
                        const char      *name,
 | 
			
		||||
                        gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  DBusWatch *watch = user_data;
 | 
			
		||||
 | 
			
		||||
  meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusWatch *
 | 
			
		||||
make_dbus_watch (MetaDBusIdleMonitor   *skeleton,
 | 
			
		||||
                 GDBusMethodInvocation *invocation,
 | 
			
		||||
                 MetaIdleMonitor       *monitor)
 | 
			
		||||
{
 | 
			
		||||
  DBusWatch *watch;
 | 
			
		||||
 | 
			
		||||
  watch = g_slice_new (DBusWatch);
 | 
			
		||||
  watch->dbus_monitor = g_object_ref (skeleton);
 | 
			
		||||
  watch->monitor = g_object_ref (monitor);
 | 
			
		||||
  watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
 | 
			
		||||
  watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
 | 
			
		||||
                                                           watch->dbus_name,
 | 
			
		||||
                                                           G_BUS_NAME_WATCHER_FLAGS_NONE,
 | 
			
		||||
                                                           NULL, /* appeared */
 | 
			
		||||
                                                           name_vanished_callback,
 | 
			
		||||
                                                           watch, NULL);
 | 
			
		||||
 | 
			
		||||
  return watch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
handle_add_idle_watch (MetaDBusIdleMonitor   *skeleton,
 | 
			
		||||
                       GDBusMethodInvocation *invocation,
 | 
			
		||||
                       guint64                interval,                  
 | 
			
		||||
                       MetaIdleMonitor       *monitor)
 | 
			
		||||
{
 | 
			
		||||
  DBusWatch *watch;
 | 
			
		||||
 | 
			
		||||
  watch = make_dbus_watch (skeleton, invocation, monitor);
 | 
			
		||||
  watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval,
 | 
			
		||||
                                                      dbus_idle_callback, watch, destroy_dbus_watch);
 | 
			
		||||
 | 
			
		||||
  meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
handle_add_user_active_watch (MetaDBusIdleMonitor   *skeleton,
 | 
			
		||||
                              GDBusMethodInvocation *invocation,
 | 
			
		||||
                              MetaIdleMonitor       *monitor)
 | 
			
		||||
{
 | 
			
		||||
  DBusWatch *watch;
 | 
			
		||||
 | 
			
		||||
  watch = make_dbus_watch (skeleton, invocation, monitor);
 | 
			
		||||
  watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor,
 | 
			
		||||
                                                             dbus_idle_callback, watch,
 | 
			
		||||
                                                             destroy_dbus_watch);
 | 
			
		||||
 | 
			
		||||
  meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
handle_remove_watch (MetaDBusIdleMonitor   *skeleton,
 | 
			
		||||
                     GDBusMethodInvocation *invocation,
 | 
			
		||||
                     guint                  id,
 | 
			
		||||
                     MetaIdleMonitor       *monitor)
 | 
			
		||||
{
 | 
			
		||||
  meta_idle_monitor_remove_watch (monitor, id);
 | 
			
		||||
  meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_device_added (ClutterDeviceManager     *device_manager,
 | 
			
		||||
                 ClutterInputDevice       *device,
 | 
			
		||||
                 GDBusObjectManagerServer *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaDBusIdleMonitor *skeleton;
 | 
			
		||||
  MetaIdleMonitor *monitor;
 | 
			
		||||
  MetaDBusObjectSkeleton *object;
 | 
			
		||||
  int device_id;
 | 
			
		||||
  gboolean is_core;
 | 
			
		||||
  char *path;
 | 
			
		||||
 | 
			
		||||
  is_core = clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER;
 | 
			
		||||
 | 
			
		||||
  if (is_core)
 | 
			
		||||
    {
 | 
			
		||||
      monitor = meta_idle_monitor_get_core ();
 | 
			
		||||
      path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      device_id = clutter_input_device_get_device_id (device);
 | 
			
		||||
      monitor = meta_idle_monitor_get_for_device (device_id);
 | 
			
		||||
      path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  skeleton = meta_dbus_idle_monitor_skeleton_new ();
 | 
			
		||||
  g_signal_connect_object (skeleton, "handle-add-idle-watch",
 | 
			
		||||
                           G_CALLBACK (handle_add_idle_watch), monitor, 0);
 | 
			
		||||
  g_signal_connect_object (skeleton, "handle-add-user-active-watch",
 | 
			
		||||
                           G_CALLBACK (handle_add_user_active_watch), monitor, 0);
 | 
			
		||||
  g_signal_connect_object (skeleton, "handle-remove-watch",
 | 
			
		||||
                           G_CALLBACK (handle_remove_watch), monitor, 0);
 | 
			
		||||
  g_signal_connect_object (skeleton, "handle-get-idletime",
 | 
			
		||||
                           G_CALLBACK (handle_get_idletime), monitor, 0);
 | 
			
		||||
 | 
			
		||||
  object = meta_dbus_object_skeleton_new (path);
 | 
			
		||||
  meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
 | 
			
		||||
 | 
			
		||||
  g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_bus_acquired (GDBusConnection *connection,
 | 
			
		||||
                 const char      *name,
 | 
			
		||||
                 gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  GDBusObjectManagerServer *manager;
 | 
			
		||||
  ClutterDeviceManager *device_manager;
 | 
			
		||||
  GSList *devices, *iter;
 | 
			
		||||
 | 
			
		||||
  manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
 | 
			
		||||
 | 
			
		||||
  device_manager = clutter_device_manager_get_default ();
 | 
			
		||||
  devices = clutter_device_manager_list_devices (device_manager);
 | 
			
		||||
 | 
			
		||||
  for (iter = devices; iter; iter = iter->next)
 | 
			
		||||
    on_device_added (device_manager, iter->data, manager);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect_object (device_manager, "device-added",
 | 
			
		||||
                           G_CALLBACK (on_device_added), manager, 0);
 | 
			
		||||
 | 
			
		||||
  g_dbus_object_manager_server_set_connection (manager, g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_name_acquired (GDBusConnection *connection,
 | 
			
		||||
                  const char      *name,
 | 
			
		||||
                  gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  meta_topic (META_DEBUG_DBUS, "Acquired name %s\n", name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_name_lost (GDBusConnection *connection,
 | 
			
		||||
              const char      *name,
 | 
			
		||||
              gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s\n", name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_idle_monitor_init_dbus (void)
 | 
			
		||||
{
 | 
			
		||||
  static int dbus_name_id;
 | 
			
		||||
 | 
			
		||||
  if (dbus_name_id > 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
 | 
			
		||||
                                 "org.gnome.Mutter.IdleMonitor",
 | 
			
		||||
                                 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
 | 
			
		||||
                                 (meta_get_replace_current_wm () ?
 | 
			
		||||
                                  G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
 | 
			
		||||
                                 on_bus_acquired,
 | 
			
		||||
                                 on_name_acquired,
 | 
			
		||||
                                 on_name_lost,
 | 
			
		||||
                                 NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								src/core/meta-xrandr-shared.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/core/meta-xrandr-shared.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* This file is shared between mutter (src/core/meta-xrandr-shared.h)
 | 
			
		||||
   and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h).
 | 
			
		||||
 | 
			
		||||
   The canonical place for all changes is mutter.
 | 
			
		||||
 | 
			
		||||
   There should be no includes in this file.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef META_XRANDR_SHARED_H
 | 
			
		||||
#define META_XRANDR_SHARED_H
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  META_POWER_SAVE_UNKNOWN = -1,
 | 
			
		||||
  META_POWER_SAVE_ON = 0,
 | 
			
		||||
  META_POWER_SAVE_STANDBY,
 | 
			
		||||
  META_POWER_SAVE_SUSPEND,
 | 
			
		||||
  META_POWER_SAVE_OFF,
 | 
			
		||||
} MetaPowerSave;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1755
									
								
								src/core/monitor-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1755
									
								
								src/core/monitor-config.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										767
									
								
								src/core/monitor-kms.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										767
									
								
								src/core/monitor-kms.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,767 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Giovanni Campagna <gcampagn@redhat.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/main.h>
 | 
			
		||||
#include <meta/errors.h>
 | 
			
		||||
#include "monitor-private.h"
 | 
			
		||||
 | 
			
		||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  drmModeConnector *connector;
 | 
			
		||||
 | 
			
		||||
  unsigned n_encoders;
 | 
			
		||||
  drmModeEncoderPtr *encoders;
 | 
			
		||||
  drmModeEncoderPtr  current_encoder;
 | 
			
		||||
 | 
			
		||||
  /* bitmasks of encoder position in the resources array */
 | 
			
		||||
  uint32_t encoder_mask;
 | 
			
		||||
  uint32_t enc_clone_mask;
 | 
			
		||||
 | 
			
		||||
  uint32_t dpms_prop_id;
 | 
			
		||||
} MetaOutputKms;
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerKms
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager parent_instance;
 | 
			
		||||
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  drmModeConnector **connectors;
 | 
			
		||||
  unsigned int       n_connectors;
 | 
			
		||||
 | 
			
		||||
  drmModeEncoder   **encoders;
 | 
			
		||||
  unsigned int       n_encoders;
 | 
			
		||||
 | 
			
		||||
  drmModeEncoder    *current_encoder;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerKmsClass
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
compare_outputs (const void *one,
 | 
			
		||||
                 const void *two)
 | 
			
		||||
{
 | 
			
		||||
  const MetaOutput *o_one = one, *o_two = two;
 | 
			
		||||
 | 
			
		||||
  return strcmp (o_one->name, o_two->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
make_output_name (drmModeConnector *connector)
 | 
			
		||||
{
 | 
			
		||||
  static const char * const connector_type_names[] = {
 | 
			
		||||
    "unknown", "VGA", "DVII", "DVID", "DVID", "Composite",
 | 
			
		||||
    "SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort",
 | 
			
		||||
    "HDMIA", "HDMIB", "TV", "eDP"
 | 
			
		||||
  };
 | 
			
		||||
  const char *connector_type_name;
 | 
			
		||||
 | 
			
		||||
  if (connector->connector_type >= 0 &&
 | 
			
		||||
      connector->connector_type < G_N_ELEMENTS (connector_type_names))
 | 
			
		||||
    connector_type_name = connector_type_names[connector->connector_type];
 | 
			
		||||
  else
 | 
			
		||||
    connector_type_name = "unknown";
 | 
			
		||||
 | 
			
		||||
  return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_output_destroy_notify (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaOutputKms *output_kms;
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
  output_kms = output->driver_private;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < output_kms->n_encoders; i++)
 | 
			
		||||
    drmModeFreeEncoder (output_kms->encoders[i]);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (MetaOutputKms, output_kms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_mode_destroy_notify (MetaMonitorMode *output)
 | 
			
		||||
{
 | 
			
		||||
  g_slice_free (drmModeModeInfo, output->driver_private);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
drm_mode_equal (gconstpointer one,
 | 
			
		||||
                gconstpointer two)
 | 
			
		||||
{
 | 
			
		||||
  return memcmp (one, two, sizeof (drmModeModeInfo)) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static guint
 | 
			
		||||
drm_mode_hash (gconstpointer ptr)
 | 
			
		||||
{
 | 
			
		||||
  const drmModeModeInfo *mode = ptr;
 | 
			
		||||
  guint hash = 0;
 | 
			
		||||
 | 
			
		||||
  hash ^= mode->clock;
 | 
			
		||||
  hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end;
 | 
			
		||||
  hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end;
 | 
			
		||||
  hash ^= mode->vrefresh;
 | 
			
		||||
  hash ^= mode->flags ^ mode->type;
 | 
			
		||||
 | 
			
		||||
  return hash;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
 | 
			
		||||
  drmModeRes *resources;
 | 
			
		||||
  GHashTable *modes;
 | 
			
		||||
  GHashTableIter iter;
 | 
			
		||||
  drmModeModeInfo *mode;
 | 
			
		||||
  unsigned int i, j, k;
 | 
			
		||||
  unsigned int n_actual_outputs;
 | 
			
		||||
  int width, height;
 | 
			
		||||
 | 
			
		||||
  resources = drmModeGetResources(manager_kms->fd);
 | 
			
		||||
  modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
 | 
			
		||||
 | 
			
		||||
  manager->max_screen_width = resources->max_width;
 | 
			
		||||
  manager->max_screen_height = resources->max_height;
 | 
			
		||||
 | 
			
		||||
  manager->power_save_mode = META_POWER_SAVE_ON;
 | 
			
		||||
 | 
			
		||||
  manager_kms->n_connectors = resources->count_connectors;
 | 
			
		||||
  manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
 | 
			
		||||
  for (i = 0; i < manager_kms->n_connectors; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeConnector *connector;
 | 
			
		||||
 | 
			
		||||
      connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]);
 | 
			
		||||
      manager_kms->connectors[i] = connector;
 | 
			
		||||
 | 
			
		||||
      if (connector->connection == DRM_MODE_CONNECTED)
 | 
			
		||||
        {
 | 
			
		||||
          /* Collect all modes for this connector */
 | 
			
		||||
          for (j = 0; j < (unsigned)connector->count_modes; j++)
 | 
			
		||||
            g_hash_table_add (modes, &connector->modes[j]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  manager_kms->n_encoders = resources->count_encoders;
 | 
			
		||||
  manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders);
 | 
			
		||||
  for (i = 0; i < manager_kms->n_encoders; i++)
 | 
			
		||||
    {
 | 
			
		||||
      manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd,
 | 
			
		||||
                                                    resources->encoders[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  manager->n_modes = g_hash_table_size (modes);
 | 
			
		||||
  manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
 | 
			
		||||
  g_hash_table_iter_init (&iter, modes);
 | 
			
		||||
  i = 0;
 | 
			
		||||
  while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode))
 | 
			
		||||
    {
 | 
			
		||||
      MetaMonitorMode *meta_mode;
 | 
			
		||||
 | 
			
		||||
      meta_mode = &manager->modes[i];
 | 
			
		||||
 | 
			
		||||
      meta_mode->mode_id = i;
 | 
			
		||||
      meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN);
 | 
			
		||||
      meta_mode->width = mode->hdisplay;
 | 
			
		||||
      meta_mode->height = mode->vdisplay;
 | 
			
		||||
      meta_mode->refresh_rate = (1000 * mode->clock /
 | 
			
		||||
                                 ((float)mode->htotal * mode->vtotal));
 | 
			
		||||
 | 
			
		||||
      meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
 | 
			
		||||
      meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
 | 
			
		||||
 | 
			
		||||
      i++;
 | 
			
		||||
    }
 | 
			
		||||
  g_hash_table_destroy (modes);
 | 
			
		||||
 | 
			
		||||
  manager->n_crtcs = resources->count_crtcs;
 | 
			
		||||
  manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
 | 
			
		||||
  width = 0; height = 0;
 | 
			
		||||
  for (i = 0; i < (unsigned)resources->count_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModeCrtc *crtc;
 | 
			
		||||
      MetaCRTC *meta_crtc;
 | 
			
		||||
 | 
			
		||||
      crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
 | 
			
		||||
 | 
			
		||||
      meta_crtc = &manager->crtcs[i];
 | 
			
		||||
 | 
			
		||||
      meta_crtc->crtc_id = crtc->crtc_id;
 | 
			
		||||
      meta_crtc->rect.x = crtc->x;
 | 
			
		||||
      meta_crtc->rect.y = crtc->y;
 | 
			
		||||
      meta_crtc->rect.width = crtc->width;
 | 
			
		||||
      meta_crtc->rect.height = crtc->height;
 | 
			
		||||
      meta_crtc->dirty = FALSE;
 | 
			
		||||
 | 
			
		||||
      /* FIXME: we can handle some transforms, with a combination of
 | 
			
		||||
         scaling and fitting, but it is very driver dependent */
 | 
			
		||||
      meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
 | 
			
		||||
      meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
 | 
			
		||||
 | 
			
		||||
      if (crtc->mode_valid)
 | 
			
		||||
        {
 | 
			
		||||
          for (j = 0; j < manager->n_modes; j++)
 | 
			
		||||
            {
 | 
			
		||||
              if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private))
 | 
			
		||||
                {
 | 
			
		||||
                  meta_crtc->current_mode = &manager->modes[j];
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width);
 | 
			
		||||
          height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      drmModeFreeCrtc (crtc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  manager->screen_width = width;
 | 
			
		||||
  manager->screen_height = height;
 | 
			
		||||
 | 
			
		||||
  manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
 | 
			
		||||
  n_actual_outputs = 0;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < manager_kms->n_connectors; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
      MetaOutputKms *output_kms;
 | 
			
		||||
      drmModeConnector *connector;
 | 
			
		||||
      GArray *crtcs;
 | 
			
		||||
      unsigned int crtc_mask;
 | 
			
		||||
 | 
			
		||||
      connector = manager_kms->connectors[i];
 | 
			
		||||
      meta_output = &manager->outputs[n_actual_outputs];
 | 
			
		||||
 | 
			
		||||
      if (connector->connection == DRM_MODE_CONNECTED)
 | 
			
		||||
	{
 | 
			
		||||
	  meta_output->output_id = connector->connector_id;
 | 
			
		||||
	  meta_output->name = make_output_name (connector);
 | 
			
		||||
	  meta_output->vendor = g_strdup ("unknown");
 | 
			
		||||
	  meta_output->product = g_strdup ("unknown");
 | 
			
		||||
	  meta_output->serial = g_strdup ("");
 | 
			
		||||
	  meta_output->width_mm = connector->mmWidth;
 | 
			
		||||
	  meta_output->height_mm = connector->mmHeight;
 | 
			
		||||
 | 
			
		||||
          if (connector->subpixel == DRM_MODE_SUBPIXEL_UNKNOWN)
 | 
			
		||||
            meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
 | 
			
		||||
          else if (connector->subpixel == DRM_MODE_SUBPIXEL_NONE)
 | 
			
		||||
            meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
 | 
			
		||||
          else
 | 
			
		||||
            meta_output->subpixel_order = connector->subpixel;
 | 
			
		||||
 | 
			
		||||
	  meta_output->n_modes = connector->count_modes;
 | 
			
		||||
	  meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
 | 
			
		||||
	  for (j = 0; j < meta_output->n_modes; j++)
 | 
			
		||||
	    {
 | 
			
		||||
	      for (k = 0; k < manager->n_modes; k++)
 | 
			
		||||
		{
 | 
			
		||||
		  if (drm_mode_equal (&connector->modes[j], manager->modes[k].driver_private))
 | 
			
		||||
		    {
 | 
			
		||||
		      meta_output->modes[j] = &manager->modes[k];
 | 
			
		||||
		      break;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	  meta_output->preferred_mode = meta_output->modes[0];
 | 
			
		||||
 | 
			
		||||
          meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms);
 | 
			
		||||
          meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
 | 
			
		||||
 | 
			
		||||
          output_kms->connector = connector;
 | 
			
		||||
          output_kms->n_encoders = connector->count_encoders;
 | 
			
		||||
          output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
 | 
			
		||||
 | 
			
		||||
          crtc_mask = 0x7F;
 | 
			
		||||
	  for (j = 0; j < output_kms->n_encoders; j++)
 | 
			
		||||
	    {
 | 
			
		||||
              output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]);
 | 
			
		||||
 | 
			
		||||
              crtc_mask &= output_kms->encoders[j]->possible_crtcs;
 | 
			
		||||
 | 
			
		||||
              if (output_kms->encoders[j]->encoder_id == connector->encoder_id)
 | 
			
		||||
                output_kms->current_encoder = output_kms->encoders[j];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
 | 
			
		||||
 | 
			
		||||
          for (j = 0; j < manager->n_crtcs; j++)
 | 
			
		||||
            {
 | 
			
		||||
              if (crtc_mask & (1 << j))
 | 
			
		||||
                {
 | 
			
		||||
                  MetaCRTC *crtc = &manager->crtcs[j];
 | 
			
		||||
                  g_array_append_val (crtcs, crtc);
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
          
 | 
			
		||||
	  meta_output->n_possible_crtcs = crtcs->len;
 | 
			
		||||
	  meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
 | 
			
		||||
 | 
			
		||||
          if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
 | 
			
		||||
            {
 | 
			
		||||
              for (j = 0; j < manager->n_crtcs; j++)
 | 
			
		||||
                {
 | 
			
		||||
                  if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id)
 | 
			
		||||
                    {
 | 
			
		||||
                      meta_output->crtc = &manager->crtcs[j];
 | 
			
		||||
                      break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            meta_output->crtc = NULL;
 | 
			
		||||
 | 
			
		||||
	  meta_output->is_primary = FALSE;
 | 
			
		||||
	  meta_output->is_presentation = FALSE;
 | 
			
		||||
 | 
			
		||||
          for (j = 0; j < (unsigned)connector->count_props; j++)
 | 
			
		||||
            {
 | 
			
		||||
              drmModePropertyPtr prop;
 | 
			
		||||
 | 
			
		||||
              prop = drmModeGetProperty(manager_kms->fd, connector->props[j]);
 | 
			
		||||
 | 
			
		||||
              if (prop)
 | 
			
		||||
                {
 | 
			
		||||
                  if ((prop->flags & DRM_MODE_PROP_ENUM) &&
 | 
			
		||||
                      strcmp(prop->name, "DPMS") == 0)
 | 
			
		||||
                    {
 | 
			
		||||
                      output_kms->dpms_prop_id = prop->prop_id;
 | 
			
		||||
                      drmModeFreeProperty(prop);
 | 
			
		||||
                      break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                  drmModeFreeProperty(prop);
 | 
			
		||||
		}
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          /* FIXME: backlight is a very driver specific thing unfortunately,
 | 
			
		||||
             every DDX does its own thing, and the dumb KMS API does not include it.
 | 
			
		||||
 | 
			
		||||
             For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
 | 
			
		||||
             (one for each major HW maker, and then some).
 | 
			
		||||
             We can't do the same because we're not root.
 | 
			
		||||
             It might be best to leave backlight out of the story and rely on the setuid
 | 
			
		||||
             helper in gnome-settings-daemon.
 | 
			
		||||
          */
 | 
			
		||||
	  meta_output->backlight_min = 0;
 | 
			
		||||
          meta_output->backlight_max = 0;
 | 
			
		||||
          meta_output->backlight = -1;
 | 
			
		||||
 | 
			
		||||
	  n_actual_outputs++;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  manager->n_outputs = n_actual_outputs;
 | 
			
		||||
  manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
 | 
			
		||||
 | 
			
		||||
  /* Sort the outputs for easier handling in MetaMonitorConfig */
 | 
			
		||||
  qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
 | 
			
		||||
 | 
			
		||||
  /* Now fix the clones.
 | 
			
		||||
     Code mostly inspired by xf86-video-modesetting. */
 | 
			
		||||
 | 
			
		||||
  /* XXX: intel hardware doesn't usually have clones, but we only have intel
 | 
			
		||||
     cards, so this code was never tested! */
 | 
			
		||||
  for (i = 0; i < manager->n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
      MetaOutputKms *output_kms;
 | 
			
		||||
 | 
			
		||||
      meta_output = &manager->outputs[i];
 | 
			
		||||
      output_kms = meta_output->driver_private;
 | 
			
		||||
 | 
			
		||||
      output_kms->enc_clone_mask = 0xff;
 | 
			
		||||
      output_kms->encoder_mask = 0;
 | 
			
		||||
 | 
			
		||||
      for (j = 0; j < output_kms->n_encoders; j++)
 | 
			
		||||
	{
 | 
			
		||||
	  for (k = 0; k < manager_kms->n_encoders; k++)
 | 
			
		||||
	    {
 | 
			
		||||
	      if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id)
 | 
			
		||||
		{
 | 
			
		||||
                  output_kms->encoder_mask |= (1 << k);
 | 
			
		||||
		  break;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
          output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < manager->n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
      MetaOutputKms *output_kms;
 | 
			
		||||
 | 
			
		||||
      meta_output = &manager->outputs[i];
 | 
			
		||||
      output_kms = meta_output->driver_private;
 | 
			
		||||
 | 
			
		||||
      if (output_kms->enc_clone_mask == 0)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      for (j = 0; j < manager->n_outputs; j++)
 | 
			
		||||
        {
 | 
			
		||||
          MetaOutput *meta_clone;
 | 
			
		||||
          MetaOutputKms *clone_kms;
 | 
			
		||||
 | 
			
		||||
          meta_clone = &manager->outputs[i];
 | 
			
		||||
          clone_kms = meta_clone->driver_private;
 | 
			
		||||
 | 
			
		||||
          if (meta_clone == meta_output)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
          if (clone_kms->encoder_mask == 0)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
          if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
 | 
			
		||||
            {
 | 
			
		||||
              meta_output->n_possible_clones++;
 | 
			
		||||
              meta_output->possible_clones = g_renew (MetaOutput *,
 | 
			
		||||
                                                      meta_output->possible_clones,
 | 
			
		||||
                                                      meta_output->n_possible_clones);
 | 
			
		||||
              meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  drmModeFreeResources (resources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
 | 
			
		||||
                                              MetaPowerSave       mode)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
 | 
			
		||||
  uint64_t state;
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
  switch (mode) {
 | 
			
		||||
  case META_POWER_SAVE_ON:
 | 
			
		||||
    state = DRM_MODE_DPMS_ON;
 | 
			
		||||
    break;
 | 
			
		||||
  case META_POWER_SAVE_STANDBY:
 | 
			
		||||
    state = DRM_MODE_DPMS_STANDBY;
 | 
			
		||||
    break;
 | 
			
		||||
  case META_POWER_SAVE_SUSPEND:
 | 
			
		||||
    state = DRM_MODE_DPMS_SUSPEND;
 | 
			
		||||
    break;
 | 
			
		||||
  case META_POWER_SAVE_OFF:
 | 
			
		||||
    state = DRM_MODE_DPMS_SUSPEND;
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < manager->n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
      MetaOutputKms *output_kms;
 | 
			
		||||
 | 
			
		||||
      meta_output = &manager->outputs[i];
 | 
			
		||||
      output_kms = meta_output->driver_private;
 | 
			
		||||
 | 
			
		||||
      if (output_kms->dpms_prop_id)
 | 
			
		||||
        {
 | 
			
		||||
          int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id,
 | 
			
		||||
                                               output_kms->dpms_prop_id, state);
 | 
			
		||||
 | 
			
		||||
          if (ok < 0)
 | 
			
		||||
            meta_warning ("Failed to set power save mode for output %s: %s\n",
 | 
			
		||||
                          meta_output->name, strerror (errno));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
crtc_free (CoglKmsCrtc *crtc)
 | 
			
		||||
{
 | 
			
		||||
  g_free (crtc->connectors);
 | 
			
		||||
  g_slice_free (CoglKmsCrtc, crtc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
                                              MetaCRTCInfo       **crtcs,
 | 
			
		||||
                                              unsigned int         n_crtcs,
 | 
			
		||||
                                              MetaOutputInfo     **outputs,
 | 
			
		||||
                                              unsigned int         n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  CoglDisplay *cogl_display;
 | 
			
		||||
  unsigned i;
 | 
			
		||||
  GList *cogl_crtcs;
 | 
			
		||||
  int width, height;
 | 
			
		||||
  gboolean ok;
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  cogl_crtcs = NULL;
 | 
			
		||||
  width = 0; height = 0;
 | 
			
		||||
  for (i = 0; i < n_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCRTCInfo *crtc_info = crtcs[i];
 | 
			
		||||
      MetaCRTC *crtc = crtc_info->crtc;
 | 
			
		||||
      CoglKmsCrtc *cogl_crtc;
 | 
			
		||||
 | 
			
		||||
      crtc->dirty = TRUE;
 | 
			
		||||
 | 
			
		||||
      cogl_crtc = g_slice_new0 (CoglKmsCrtc);
 | 
			
		||||
      cogl_crtcs = g_list_prepend (cogl_crtcs, cogl_crtc);
 | 
			
		||||
 | 
			
		||||
      if (crtc_info->mode == NULL)
 | 
			
		||||
        {
 | 
			
		||||
          cogl_crtc->id = crtc->crtc_id;
 | 
			
		||||
          cogl_crtc->x = 0;
 | 
			
		||||
          cogl_crtc->y = 0;
 | 
			
		||||
          cogl_crtc->count = 0;
 | 
			
		||||
          memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
 | 
			
		||||
          cogl_crtc->connectors = NULL;
 | 
			
		||||
          cogl_crtc->count = 0;
 | 
			
		||||
 | 
			
		||||
          crtc->rect.x = 0;
 | 
			
		||||
          crtc->rect.y = 0;
 | 
			
		||||
          crtc->rect.width = 0;
 | 
			
		||||
          crtc->rect.height = 0;
 | 
			
		||||
          crtc->current_mode = NULL;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          MetaMonitorMode *mode;
 | 
			
		||||
          uint32_t *outputs;
 | 
			
		||||
          unsigned int j, n_outputs;
 | 
			
		||||
 | 
			
		||||
          mode = crtc_info->mode;
 | 
			
		||||
 | 
			
		||||
          cogl_crtc->id = crtc->crtc_id;
 | 
			
		||||
          cogl_crtc->x = crtc_info->x;
 | 
			
		||||
          cogl_crtc->y = crtc_info->y;
 | 
			
		||||
          cogl_crtc->count = n_outputs = crtc_info->outputs->len;
 | 
			
		||||
          cogl_crtc->connectors = outputs = g_new (uint32_t, n_outputs);
 | 
			
		||||
 | 
			
		||||
          for (j = 0; j < n_outputs; j++)
 | 
			
		||||
            {
 | 
			
		||||
              MetaOutput *output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
 | 
			
		||||
 | 
			
		||||
              outputs[j] = output->output_id;
 | 
			
		||||
 | 
			
		||||
              output->dirty = TRUE;
 | 
			
		||||
              output->crtc = crtc;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private,
 | 
			
		||||
                  sizeof (drmModeModeInfo));
 | 
			
		||||
 | 
			
		||||
          width = MAX (width, crtc_info->x + crtc_info->mode->width);
 | 
			
		||||
          height = MAX (height, crtc_info->y + crtc_info->mode->height);
 | 
			
		||||
 | 
			
		||||
          crtc->rect.x = crtc_info->x;
 | 
			
		||||
          crtc->rect.y = crtc_info->y;
 | 
			
		||||
          crtc->rect.width = mode->width;
 | 
			
		||||
          crtc->rect.height = mode->height;
 | 
			
		||||
          crtc->current_mode = mode;
 | 
			
		||||
          crtc->transform = crtc_info->transform;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list */
 | 
			
		||||
  for (i = 0; i < manager->n_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCRTC *crtc = &manager->crtcs[i];
 | 
			
		||||
      CoglKmsCrtc *cogl_crtc;
 | 
			
		||||
 | 
			
		||||
      crtc->logical_monitor = NULL;
 | 
			
		||||
 | 
			
		||||
      if (crtc->dirty)
 | 
			
		||||
        {
 | 
			
		||||
          crtc->dirty = FALSE;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      cogl_crtc = g_slice_new0 (CoglKmsCrtc);
 | 
			
		||||
      cogl_crtcs = g_list_prepend (cogl_crtcs, cogl_crtc);
 | 
			
		||||
 | 
			
		||||
      cogl_crtc->id = crtc->crtc_id;
 | 
			
		||||
      cogl_crtc->x = 0;
 | 
			
		||||
      cogl_crtc->y = 0;
 | 
			
		||||
      cogl_crtc->count = 0;
 | 
			
		||||
      memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
 | 
			
		||||
      cogl_crtc->connectors = NULL;
 | 
			
		||||
      cogl_crtc->count = 0;
 | 
			
		||||
 | 
			
		||||
      crtc->rect.x = 0;
 | 
			
		||||
      crtc->rect.y = 0;
 | 
			
		||||
      crtc->rect.width = 0;
 | 
			
		||||
      crtc->rect.height = 0;
 | 
			
		||||
      crtc->current_mode = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  backend = clutter_get_default_backend ();
 | 
			
		||||
  cogl_context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
  cogl_display = cogl_context_get_display (cogl_context);
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  ok = cogl_kms_display_set_layout (cogl_display, width, height, cogl_crtcs, &error);
 | 
			
		||||
  g_list_free_full (cogl_crtcs, (GDestroyNotify) crtc_free);
 | 
			
		||||
 | 
			
		||||
  if (!ok)
 | 
			
		||||
    {
 | 
			
		||||
      meta_warning ("Applying display configuration failed: %s\n", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutputInfo *output_info = outputs[i];
 | 
			
		||||
      MetaOutput *output = output_info->output;
 | 
			
		||||
 | 
			
		||||
      output->is_primary = output_info->is_primary;
 | 
			
		||||
      output->is_presentation = output_info->is_presentation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable outputs not mentioned in the list */
 | 
			
		||||
  for (i = 0; i < manager->n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *output = &manager->outputs[i];
 | 
			
		||||
 | 
			
		||||
      if (output->dirty)
 | 
			
		||||
        {
 | 
			
		||||
          output->dirty = FALSE;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      output->crtc = NULL;
 | 
			
		||||
      output->is_primary = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  manager->screen_width = width;
 | 
			
		||||
  manager->screen_height = height;
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_rebuild_derived (manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager  *manager,
 | 
			
		||||
                                         MetaCRTC            *crtc,
 | 
			
		||||
                                         gsize               *size,
 | 
			
		||||
                                         unsigned short     **red,
 | 
			
		||||
                                         unsigned short     **green,
 | 
			
		||||
                                         unsigned short     **blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
 | 
			
		||||
  drmModeCrtc *kms_crtc;
 | 
			
		||||
 | 
			
		||||
  kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id);
 | 
			
		||||
 | 
			
		||||
  *size = kms_crtc->gamma_size;
 | 
			
		||||
  *red = g_new (unsigned short, *size);
 | 
			
		||||
  *green = g_new (unsigned short, *size);
 | 
			
		||||
  *blue = g_new (unsigned short, *size);
 | 
			
		||||
 | 
			
		||||
  drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue);
 | 
			
		||||
 | 
			
		||||
  drmModeFreeCrtc (kms_crtc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
 | 
			
		||||
                                         MetaCRTC           *crtc,
 | 
			
		||||
                                         gsize               size,
 | 
			
		||||
                                         unsigned short     *red,
 | 
			
		||||
                                         unsigned short     *green,
 | 
			
		||||
                                         unsigned short     *blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
 | 
			
		||||
 | 
			
		||||
  drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
{
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *cogl_context;
 | 
			
		||||
  CoglDisplay *cogl_display;
 | 
			
		||||
  CoglRenderer *cogl_renderer;
 | 
			
		||||
 | 
			
		||||
  backend = clutter_get_default_backend ();
 | 
			
		||||
  cogl_context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
  cogl_display = cogl_context_get_display (cogl_context);
 | 
			
		||||
  cogl_renderer = cogl_display_get_renderer (cogl_display);
 | 
			
		||||
 | 
			
		||||
  manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < manager_kms->n_encoders; i++)
 | 
			
		||||
    drmModeFreeEncoder (manager_kms->encoders[i]);
 | 
			
		||||
  for (i = 0; i < manager_kms->n_connectors; i++)
 | 
			
		||||
    drmModeFreeConnector (manager_kms->connectors[i]);
 | 
			
		||||
 | 
			
		||||
  g_free (manager_kms->encoders);
 | 
			
		||||
  g_free (manager_kms->connectors);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_monitor_manager_kms_finalize;
 | 
			
		||||
 | 
			
		||||
  manager_class->read_current = meta_monitor_manager_kms_read_current;
 | 
			
		||||
  manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration;
 | 
			
		||||
  manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode;
 | 
			
		||||
  manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma;
 | 
			
		||||
  manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										408
									
								
								src/core/monitor-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								src/core/monitor-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,408 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \file screen-private.h  Handling of monitor configuration
 | 
			
		||||
 *
 | 
			
		||||
 * Managing multiple monitors
 | 
			
		||||
 * This file contains structures and functions that handle
 | 
			
		||||
 * multiple monitors, including reading the current configuration
 | 
			
		||||
 * and available hardware, and applying it.
 | 
			
		||||
 *
 | 
			
		||||
 * This interface is private to mutter, API users should look
 | 
			
		||||
 * at MetaScreen instead.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2001 Havoc Pennington
 | 
			
		||||
 * Copyright (C) 2003 Rob Adams
 | 
			
		||||
 * Copyright (C) 2004-2006 Elijah Newren
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_MONITOR_PRIVATE_H
 | 
			
		||||
#define META_MONITOR_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <cogl/cogl.h>
 | 
			
		||||
 | 
			
		||||
#include "display-private.h"
 | 
			
		||||
#include <meta/screen.h>
 | 
			
		||||
#include "stack-tracker.h"
 | 
			
		||||
#include "ui.h"
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include "meta-xrandr-shared.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-dbus-xrandr.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaMonitorManagerClass    MetaMonitorManagerClass;
 | 
			
		||||
typedef struct _MetaMonitorManager         MetaMonitorManager;
 | 
			
		||||
typedef struct _MetaMonitorConfigClass    MetaMonitorConfigClass;
 | 
			
		||||
typedef struct _MetaMonitorConfig         MetaMonitorConfig;
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_WAYLAND
 | 
			
		||||
enum wl_output_transform {
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_NORMAL,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_90,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_180,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_270,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_FLIPPED,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_FLIPPED_90,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_FLIPPED_180,
 | 
			
		||||
  WL_OUTPUT_TRANSFORM_FLIPPED_270
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaOutput MetaOutput;
 | 
			
		||||
typedef struct _MetaCRTC MetaCRTC;
 | 
			
		||||
typedef struct _MetaMonitorMode MetaMonitorMode;
 | 
			
		||||
typedef struct _MetaMonitorInfo MetaMonitorInfo;
 | 
			
		||||
typedef struct _MetaCRTCInfo MetaCRTCInfo;
 | 
			
		||||
typedef struct _MetaOutputInfo MetaOutputInfo;
 | 
			
		||||
 | 
			
		||||
struct _MetaOutput
 | 
			
		||||
{
 | 
			
		||||
  /* The CRTC driving this output, NULL if the output is not enabled */
 | 
			
		||||
  MetaCRTC *crtc;
 | 
			
		||||
  /* The low-level ID of this output, used to apply back configuration */
 | 
			
		||||
  glong output_id;
 | 
			
		||||
  char *name;
 | 
			
		||||
  char *vendor;
 | 
			
		||||
  char *product;
 | 
			
		||||
  char *serial;
 | 
			
		||||
  int width_mm;
 | 
			
		||||
  int height_mm;
 | 
			
		||||
  CoglSubpixelOrder subpixel_order;
 | 
			
		||||
 | 
			
		||||
  MetaMonitorMode *preferred_mode;
 | 
			
		||||
  MetaMonitorMode **modes;
 | 
			
		||||
  unsigned int n_modes;
 | 
			
		||||
 | 
			
		||||
  MetaCRTC **possible_crtcs;
 | 
			
		||||
  unsigned int n_possible_crtcs;
 | 
			
		||||
 | 
			
		||||
  MetaOutput **possible_clones;
 | 
			
		||||
  unsigned int n_possible_clones;
 | 
			
		||||
 | 
			
		||||
  int backlight;
 | 
			
		||||
  int backlight_min;
 | 
			
		||||
  int backlight_max;
 | 
			
		||||
 | 
			
		||||
  /* Used when changing configuration */
 | 
			
		||||
  gboolean dirty;
 | 
			
		||||
 | 
			
		||||
  /* The low-level bits used to build the high-level info
 | 
			
		||||
     in MetaMonitorInfo
 | 
			
		||||
 | 
			
		||||
     XXX: flags maybe?
 | 
			
		||||
     There is a lot of code that uses MonitorInfo->is_primary,
 | 
			
		||||
     but nobody uses MetaOutput yet
 | 
			
		||||
  */
 | 
			
		||||
  gboolean is_primary;
 | 
			
		||||
  gboolean is_presentation;
 | 
			
		||||
 | 
			
		||||
  gpointer driver_private;
 | 
			
		||||
  GDestroyNotify driver_notify;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaCRTC
 | 
			
		||||
{
 | 
			
		||||
  glong crtc_id;
 | 
			
		||||
  MetaRectangle rect;
 | 
			
		||||
  MetaMonitorMode *current_mode;
 | 
			
		||||
  enum wl_output_transform transform;
 | 
			
		||||
  unsigned int all_transforms;
 | 
			
		||||
 | 
			
		||||
  /* Only used to build the logical configuration
 | 
			
		||||
     from the HW one
 | 
			
		||||
  */
 | 
			
		||||
  MetaMonitorInfo *logical_monitor;
 | 
			
		||||
 | 
			
		||||
  /* Used when changing configuration */
 | 
			
		||||
  gboolean dirty;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorMode
 | 
			
		||||
{
 | 
			
		||||
  /* The low-level ID of this mode, used to apply back configuration */
 | 
			
		||||
  glong mode_id;
 | 
			
		||||
  char *name;
 | 
			
		||||
 | 
			
		||||
  int width;
 | 
			
		||||
  int height;
 | 
			
		||||
  float refresh_rate;
 | 
			
		||||
 | 
			
		||||
  gpointer driver_private;
 | 
			
		||||
  GDestroyNotify driver_notify;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MetaMonitorInfo:
 | 
			
		||||
 *
 | 
			
		||||
 * A structure with high-level information about monitors.
 | 
			
		||||
 * This corresponds to a subset of the compositor coordinate space.
 | 
			
		||||
 * Clones are only reported once, irrespective of the way
 | 
			
		||||
 * they're implemented (two CRTCs configured for the same
 | 
			
		||||
 * coordinates or one CRTCs driving two outputs). Inactive CRTCs
 | 
			
		||||
 * are ignored, and so are disabled outputs.
 | 
			
		||||
 */
 | 
			
		||||
struct _MetaMonitorInfo
 | 
			
		||||
{
 | 
			
		||||
  int number;
 | 
			
		||||
  int xinerama_index;
 | 
			
		||||
  MetaRectangle rect;
 | 
			
		||||
  gboolean is_primary;
 | 
			
		||||
  gboolean is_presentation; /* XXX: not yet used */
 | 
			
		||||
  gboolean in_fullscreen;
 | 
			
		||||
 | 
			
		||||
  /* The primary or first output for this monitor, 0 if we can't figure out.
 | 
			
		||||
     This is a XID when using XRandR, otherwise a KMS id (not implemented).
 | 
			
		||||
     In any case, it can be matched to an output_id of a MetaOutput.
 | 
			
		||||
 | 
			
		||||
     This is used as an opaque token on reconfiguration when switching from
 | 
			
		||||
     clone to extened, to decide on what output the windows should go next
 | 
			
		||||
     (it's an attempt to keep windows on the same monitor, and preferably on
 | 
			
		||||
     the primary one).
 | 
			
		||||
  */
 | 
			
		||||
  glong output_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * MetaCRTCInfo:
 | 
			
		||||
 * This represents the writable part of a CRTC, as deserialized from DBus
 | 
			
		||||
 * or built by MetaMonitorConfig
 | 
			
		||||
 *
 | 
			
		||||
 * Note: differently from the other structures in this file, MetaCRTCInfo
 | 
			
		||||
 * is handled by pointer. This is to accomodate the usage in MetaMonitorConfig
 | 
			
		||||
 */
 | 
			
		||||
struct _MetaCRTCInfo {
 | 
			
		||||
  MetaCRTC                 *crtc;
 | 
			
		||||
  MetaMonitorMode          *mode;
 | 
			
		||||
  int                       x;
 | 
			
		||||
  int                       y;
 | 
			
		||||
  enum wl_output_transform  transform;
 | 
			
		||||
  GPtrArray                *outputs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * MetaOutputInfo:
 | 
			
		||||
 * this is the same as MetaOutputInfo, but for CRTCs
 | 
			
		||||
 */
 | 
			
		||||
struct _MetaOutputInfo {
 | 
			
		||||
  MetaOutput  *output;
 | 
			
		||||
  gboolean     is_primary;
 | 
			
		||||
  gboolean     is_presentation;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_MONITOR_MANAGER            (meta_monitor_manager_get_type ())
 | 
			
		||||
#define META_MONITOR_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager))
 | 
			
		||||
#define META_MONITOR_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
 | 
			
		||||
#define META_IS_MONITOR_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER))
 | 
			
		||||
#define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_MONITOR_MANAGER))
 | 
			
		||||
#define META_MONITOR_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManager
 | 
			
		||||
{
 | 
			
		||||
  MetaDBusDisplayConfigSkeleton parent_instance;
 | 
			
		||||
 | 
			
		||||
  /* XXX: this structure is very badly
 | 
			
		||||
     packed, but I like the logical organization
 | 
			
		||||
     of fields */
 | 
			
		||||
 | 
			
		||||
  gboolean in_init;
 | 
			
		||||
  unsigned int serial;
 | 
			
		||||
 | 
			
		||||
  MetaPowerSave power_save_mode;
 | 
			
		||||
 | 
			
		||||
  int max_screen_width;
 | 
			
		||||
  int max_screen_height;
 | 
			
		||||
  int screen_width;
 | 
			
		||||
  int screen_height;
 | 
			
		||||
 | 
			
		||||
  /* Outputs refer to physical screens,
 | 
			
		||||
     CRTCs refer to stuff that can drive outputs
 | 
			
		||||
     (like encoders, but less tied to the HW),
 | 
			
		||||
     while monitor_infos refer to logical ones.
 | 
			
		||||
 | 
			
		||||
     See also the comment in monitor-private.h
 | 
			
		||||
  */
 | 
			
		||||
  MetaOutput *outputs;
 | 
			
		||||
  unsigned int n_outputs;
 | 
			
		||||
 | 
			
		||||
  MetaMonitorMode *modes;
 | 
			
		||||
  unsigned int n_modes;
 | 
			
		||||
 | 
			
		||||
  MetaCRTC *crtcs;
 | 
			
		||||
  unsigned int n_crtcs;
 | 
			
		||||
 | 
			
		||||
  MetaMonitorInfo *monitor_infos;
 | 
			
		||||
  unsigned int n_monitor_infos;
 | 
			
		||||
  int primary_monitor_index;
 | 
			
		||||
 | 
			
		||||
  int dbus_name_id;
 | 
			
		||||
 | 
			
		||||
  int persistent_timeout_id;
 | 
			
		||||
  MetaMonitorConfig *config;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerClass
 | 
			
		||||
{
 | 
			
		||||
  MetaDBusDisplayConfigSkeletonClass parent_class;
 | 
			
		||||
 | 
			
		||||
  void (*read_current) (MetaMonitorManager *);
 | 
			
		||||
 | 
			
		||||
  char* (*get_edid_file) (MetaMonitorManager *,
 | 
			
		||||
                          MetaOutput         *);
 | 
			
		||||
  GBytes* (*read_edid) (MetaMonitorManager *,
 | 
			
		||||
                        MetaOutput         *);
 | 
			
		||||
 | 
			
		||||
  void (*apply_configuration) (MetaMonitorManager  *,
 | 
			
		||||
                               MetaCRTCInfo       **,
 | 
			
		||||
                               unsigned int         ,
 | 
			
		||||
                               MetaOutputInfo     **,
 | 
			
		||||
                               unsigned int);
 | 
			
		||||
 | 
			
		||||
  void (*set_power_save_mode) (MetaMonitorManager *,
 | 
			
		||||
                               MetaPowerSave);
 | 
			
		||||
 | 
			
		||||
  void (*change_backlight) (MetaMonitorManager *,
 | 
			
		||||
                            MetaOutput         *,
 | 
			
		||||
                            int);
 | 
			
		||||
 | 
			
		||||
  void (*get_crtc_gamma) (MetaMonitorManager  *,
 | 
			
		||||
                          MetaCRTC            *,
 | 
			
		||||
                          gsize               *,
 | 
			
		||||
                          unsigned short     **,
 | 
			
		||||
                          unsigned short     **,
 | 
			
		||||
                          unsigned short     **);
 | 
			
		||||
  void (*set_crtc_gamma) (MetaMonitorManager *,
 | 
			
		||||
                          MetaCRTC           *,
 | 
			
		||||
                          gsize               ,
 | 
			
		||||
                          unsigned short     *,
 | 
			
		||||
                          unsigned short     *,
 | 
			
		||||
                          unsigned short     *);
 | 
			
		||||
 | 
			
		||||
  gboolean (*handle_xevent) (MetaMonitorManager *,
 | 
			
		||||
                             XEvent             *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType meta_monitor_manager_get_type (void);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_initialize (void);
 | 
			
		||||
MetaMonitorManager *meta_monitor_manager_get  (void);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_init_dbus         (MetaMonitorManager *manager,
 | 
			
		||||
                                                            GAsyncReadyCallback callback,
 | 
			
		||||
                                                            gpointer            user_data);
 | 
			
		||||
gboolean            meta_monitor_manager_init_dbus_finish  (MetaMonitorManager *manager,
 | 
			
		||||
                                                            GAsyncResult       *result,
 | 
			
		||||
                                                            GError            **error);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_rebuild_derived   (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
MetaMonitorInfo    *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
 | 
			
		||||
							    unsigned int       *n_infos);
 | 
			
		||||
 | 
			
		||||
MetaOutput         *meta_monitor_manager_get_outputs       (MetaMonitorManager *manager,
 | 
			
		||||
							    unsigned int       *n_outputs);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_get_resources     (MetaMonitorManager  *manager,
 | 
			
		||||
                                                            MetaMonitorMode    **modes,
 | 
			
		||||
                                                            unsigned int        *n_modes,
 | 
			
		||||
                                                            MetaCRTC           **crtcs,
 | 
			
		||||
                                                            unsigned int        *n_crtcs,
 | 
			
		||||
                                                            MetaOutput         **outputs,
 | 
			
		||||
                                                            unsigned int        *n_outputs);
 | 
			
		||||
 | 
			
		||||
int                 meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
gboolean            meta_monitor_manager_handle_xevent     (MetaMonitorManager *manager,
 | 
			
		||||
                                                            XEvent             *event);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_get_screen_size   (MetaMonitorManager *manager,
 | 
			
		||||
                                                            int                *width,
 | 
			
		||||
                                                            int                *height);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
 | 
			
		||||
                                                            int                *width,
 | 
			
		||||
                                                            int                *height);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_apply_configuration (MetaMonitorManager  *manager,
 | 
			
		||||
                                                              MetaCRTCInfo       **crtcs,
 | 
			
		||||
                                                              unsigned int         n_crtcs,
 | 
			
		||||
                                                              MetaOutputInfo     **outputs,
 | 
			
		||||
                                                              unsigned int         n_outputs);
 | 
			
		||||
 | 
			
		||||
void                meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
 | 
			
		||||
                                                                gboolean            ok);
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_MONITOR_MANAGER_XRANDR            (meta_monitor_manager_xrandr_get_type ())
 | 
			
		||||
#define META_MONITOR_MANAGER_XRANDR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr))
 | 
			
		||||
#define META_MONITOR_MANAGER_XRANDR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
 | 
			
		||||
#define META_IS_MONITOR_MANAGER_XRANDR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR))
 | 
			
		||||
#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_MONITOR_MANAGER_XRANDR))
 | 
			
		||||
#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaMonitorManagerXrandrClass    MetaMonitorManagerXrandrClass;
 | 
			
		||||
typedef struct _MetaMonitorManagerXrandr         MetaMonitorManagerXrandr;
 | 
			
		||||
 | 
			
		||||
GType meta_monitor_manager_xrandr_get_type (void);
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_MONITOR_MANAGER_KMS            (meta_monitor_manager_kms_get_type ())
 | 
			
		||||
#define META_MONITOR_MANAGER_KMS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms))
 | 
			
		||||
#define META_MONITOR_MANAGER_KMS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
 | 
			
		||||
#define META_IS_MONITOR_MANAGER_KMS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS))
 | 
			
		||||
#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_MONITOR_MANAGER_KMS))
 | 
			
		||||
#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaMonitorManagerKmsClass    MetaMonitorManagerKmsClass;
 | 
			
		||||
typedef struct _MetaMonitorManagerKms         MetaMonitorManagerKms;
 | 
			
		||||
 | 
			
		||||
GType meta_monitor_manager_kms_get_type (void);
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_MONITOR_CONFIG            (meta_monitor_config_get_type ())
 | 
			
		||||
#define META_MONITOR_CONFIG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
 | 
			
		||||
#define META_MONITOR_CONFIG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
 | 
			
		||||
#define META_IS_MONITOR_CONFIG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
 | 
			
		||||
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_MONITOR_CONFIG))
 | 
			
		||||
#define META_MONITOR_CONFIG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
 | 
			
		||||
 | 
			
		||||
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
MetaMonitorConfig *meta_monitor_config_new (void);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_monitor_config_match_current (MetaMonitorConfig  *config,
 | 
			
		||||
                                                      MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
gboolean           meta_monitor_config_apply_stored (MetaMonitorConfig  *config,
 | 
			
		||||
                                                     MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
void               meta_monitor_config_make_default (MetaMonitorConfig  *config,
 | 
			
		||||
                                                     MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
void               meta_monitor_config_update_current (MetaMonitorConfig  *config,
 | 
			
		||||
                                                       MetaMonitorManager *manager);
 | 
			
		||||
void               meta_monitor_config_make_persistent (MetaMonitorConfig *config);
 | 
			
		||||
 | 
			
		||||
void               meta_monitor_config_restore_previous (MetaMonitorConfig  *config,
 | 
			
		||||
                                                         MetaMonitorManager *manager);
 | 
			
		||||
 | 
			
		||||
void               meta_crtc_info_free   (MetaCRTCInfo   *info);
 | 
			
		||||
void               meta_output_info_free (MetaOutputInfo *info);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										846
									
								
								src/core/monitor-xrandr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										846
									
								
								src/core/monitor-xrandr.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,846 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2001, 2002 Havoc Pennington
 | 
			
		||||
 * Copyright (C) 2002, 2003 Red Hat Inc.
 | 
			
		||||
 * Some ICCCM manager selection code derived from fvwm2,
 | 
			
		||||
 * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
 | 
			
		||||
 * Copyright (C) 2003 Rob Adams
 | 
			
		||||
 * Copyright (C) 2004-2006 Elijah Newren
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <X11/Xatom.h>
 | 
			
		||||
#include <X11/extensions/Xrandr.h>
 | 
			
		||||
#include <X11/extensions/dpms.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/main.h>
 | 
			
		||||
#include <meta/errors.h>
 | 
			
		||||
#include "monitor-private.h"
 | 
			
		||||
 | 
			
		||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerXrandr
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager parent_instance;
 | 
			
		||||
 | 
			
		||||
  Display *xdisplay;
 | 
			
		||||
  XRRScreenResources *resources;
 | 
			
		||||
  int time;
 | 
			
		||||
  int rr_event_base;
 | 
			
		||||
  int rr_error_base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerXrandrClass
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr, META_TYPE_MONITOR_MANAGER);
 | 
			
		||||
 | 
			
		||||
static enum wl_output_transform
 | 
			
		||||
wl_transform_from_xrandr (Rotation rotation)
 | 
			
		||||
{
 | 
			
		||||
  static const enum wl_output_transform y_reflected_map[4] = {
 | 
			
		||||
    WL_OUTPUT_TRANSFORM_FLIPPED_180,
 | 
			
		||||
    WL_OUTPUT_TRANSFORM_FLIPPED_90,
 | 
			
		||||
    WL_OUTPUT_TRANSFORM_FLIPPED,
 | 
			
		||||
    WL_OUTPUT_TRANSFORM_FLIPPED_270
 | 
			
		||||
  };
 | 
			
		||||
  enum wl_output_transform ret;
 | 
			
		||||
 | 
			
		||||
  switch (rotation & 0x7F)
 | 
			
		||||
    {
 | 
			
		||||
    default:
 | 
			
		||||
    case RR_Rotate_0:
 | 
			
		||||
      ret = WL_OUTPUT_TRANSFORM_NORMAL;
 | 
			
		||||
      break;
 | 
			
		||||
    case RR_Rotate_90:
 | 
			
		||||
      ret = WL_OUTPUT_TRANSFORM_90;
 | 
			
		||||
      break;
 | 
			
		||||
    case RR_Rotate_180:
 | 
			
		||||
      ret = WL_OUTPUT_TRANSFORM_180;
 | 
			
		||||
      break;
 | 
			
		||||
    case RR_Rotate_270:
 | 
			
		||||
      ret = WL_OUTPUT_TRANSFORM_270;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (rotation & RR_Reflect_X)
 | 
			
		||||
    return ret + 4;
 | 
			
		||||
  else if (rotation & RR_Reflect_Y)
 | 
			
		||||
    return y_reflected_map[ret];
 | 
			
		||||
  else
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)
 | 
			
		||||
 | 
			
		||||
static unsigned int
 | 
			
		||||
wl_transform_from_xrandr_all (Rotation rotation)
 | 
			
		||||
{
 | 
			
		||||
  unsigned ret;
 | 
			
		||||
 | 
			
		||||
  /* Handle the common cases first (none or all) */
 | 
			
		||||
  if (rotation == 0 || rotation == RR_Rotate_0)
 | 
			
		||||
    return (1 << WL_OUTPUT_TRANSFORM_NORMAL);
 | 
			
		||||
 | 
			
		||||
  /* All rotations and one reflection -> all of them by composition */
 | 
			
		||||
  if ((rotation & ALL_ROTATIONS) &&
 | 
			
		||||
      ((rotation & RR_Reflect_X) || (rotation & RR_Reflect_Y)))
 | 
			
		||||
    return ALL_WL_TRANSFORMS;
 | 
			
		||||
 | 
			
		||||
  ret = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
 | 
			
		||||
  if (rotation & RR_Rotate_90)
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_90;
 | 
			
		||||
  if (rotation & RR_Rotate_180)
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_180;
 | 
			
		||||
  if (rotation & RR_Rotate_270)
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_270;
 | 
			
		||||
  if (rotation & (RR_Rotate_0 | RR_Reflect_X))
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED;
 | 
			
		||||
  if (rotation & (RR_Rotate_90 | RR_Reflect_X))
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_90;
 | 
			
		||||
  if (rotation & (RR_Rotate_180 | RR_Reflect_X))
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_180;
 | 
			
		||||
  if (rotation & (RR_Rotate_270 | RR_Reflect_X))
 | 
			
		||||
    ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_270;
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                                MetaOutput               *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
  gboolean value;
 | 
			
		||||
  Atom actual_type;
 | 
			
		||||
  int actual_format;
 | 
			
		||||
  unsigned long nitems, bytes_after;
 | 
			
		||||
  unsigned char *buffer;
 | 
			
		||||
 | 
			
		||||
  XRRGetOutputProperty (manager_xrandr->xdisplay,
 | 
			
		||||
                        (XID)output->output_id,
 | 
			
		||||
                        display->atom__MUTTER_PRESENTATION_OUTPUT,
 | 
			
		||||
                        0, G_MAXLONG, False, False, XA_CARDINAL,
 | 
			
		||||
                        &actual_type, &actual_format,
 | 
			
		||||
                        &nitems, &bytes_after, &buffer);
 | 
			
		||||
 | 
			
		||||
  if (actual_type != XA_CARDINAL || actual_format != 32 ||
 | 
			
		||||
      nitems < 1)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  value = ((int*)buffer)[0];
 | 
			
		||||
 | 
			
		||||
  XFree (buffer);
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
normalize_backlight (MetaOutput *output,
 | 
			
		||||
                     int         hw_value)
 | 
			
		||||
{
 | 
			
		||||
  return round((double)(hw_value - output->backlight_min) /
 | 
			
		||||
               (output->backlight_max - output->backlight_min) * 100.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                             MetaOutput               *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
  gboolean value;
 | 
			
		||||
  Atom actual_type;
 | 
			
		||||
  int actual_format;
 | 
			
		||||
  unsigned long nitems, bytes_after;
 | 
			
		||||
  unsigned char *buffer;
 | 
			
		||||
 | 
			
		||||
  XRRGetOutputProperty (manager_xrandr->xdisplay,
 | 
			
		||||
                        (XID)output->output_id,
 | 
			
		||||
                        display->atom_BACKLIGHT,
 | 
			
		||||
                        0, G_MAXLONG, False, False, XA_INTEGER,
 | 
			
		||||
                        &actual_type, &actual_format,
 | 
			
		||||
                        &nitems, &bytes_after, &buffer);
 | 
			
		||||
 | 
			
		||||
  if (actual_type != XA_INTEGER || actual_format != 32 ||
 | 
			
		||||
      nitems < 1)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  value = ((int*)buffer)[0];
 | 
			
		||||
 | 
			
		||||
  XFree (buffer);
 | 
			
		||||
  return normalize_backlight (output, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_get_backlight_limits_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                                    MetaOutput               *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
  XRRPropertyInfo *info;
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (display);
 | 
			
		||||
  info = XRRQueryOutputProperty (manager_xrandr->xdisplay,
 | 
			
		||||
                                 (XID)output->output_id,
 | 
			
		||||
                                 display->atom_BACKLIGHT);
 | 
			
		||||
  meta_error_trap_pop (display);
 | 
			
		||||
 | 
			
		||||
  if (info == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("could not get output property for %s\n", output->name);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!info->range || info->num_values != 2)
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("backlight %s was not range\n", output->name);
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  output->backlight_min = info->values[0];
 | 
			
		||||
  output->backlight_max = info->values[1];
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
  XFree (info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
compare_outputs (const void *one,
 | 
			
		||||
                 const void *two)
 | 
			
		||||
{
 | 
			
		||||
  const MetaOutput *o_one = one, *o_two = two;
 | 
			
		||||
 | 
			
		||||
  return strcmp (o_one->name, o_two->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  XRRScreenResources *resources;
 | 
			
		||||
  RROutput primary_output;
 | 
			
		||||
  unsigned int i, j, k;
 | 
			
		||||
  unsigned int n_actual_outputs;
 | 
			
		||||
  int min_width, min_height;
 | 
			
		||||
  Screen *screen;
 | 
			
		||||
  BOOL dpms_capable, dpms_enabled;
 | 
			
		||||
  CARD16 dpms_state;
 | 
			
		||||
 | 
			
		||||
  if (manager_xrandr->resources)
 | 
			
		||||
    XRRFreeScreenResources (manager_xrandr->resources);
 | 
			
		||||
  manager_xrandr->resources = NULL;
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (meta_get_display ());
 | 
			
		||||
  dpms_capable = DPMSCapable (manager_xrandr->xdisplay);
 | 
			
		||||
  meta_error_trap_pop (meta_get_display ());
 | 
			
		||||
 | 
			
		||||
  if (dpms_capable &&
 | 
			
		||||
      DPMSInfo (manager_xrandr->xdisplay, &dpms_state, &dpms_enabled) &&
 | 
			
		||||
      dpms_enabled)
 | 
			
		||||
    {
 | 
			
		||||
      switch (dpms_state)
 | 
			
		||||
	{
 | 
			
		||||
	case DPMSModeOn:
 | 
			
		||||
	  manager->power_save_mode = META_POWER_SAVE_ON;
 | 
			
		||||
	case DPMSModeStandby:
 | 
			
		||||
	  manager->power_save_mode = META_POWER_SAVE_STANDBY;
 | 
			
		||||
	case DPMSModeSuspend:
 | 
			
		||||
	  manager->power_save_mode = META_POWER_SAVE_SUSPEND;
 | 
			
		||||
	case DPMSModeOff:
 | 
			
		||||
	  manager->power_save_mode = META_POWER_SAVE_OFF;
 | 
			
		||||
	default:
 | 
			
		||||
	  manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  XRRGetScreenSizeRange (manager_xrandr->xdisplay, DefaultRootWindow (manager_xrandr->xdisplay),
 | 
			
		||||
			 &min_width,
 | 
			
		||||
			 &min_height,
 | 
			
		||||
			 &manager->max_screen_width,
 | 
			
		||||
			 &manager->max_screen_height);
 | 
			
		||||
 | 
			
		||||
  screen = ScreenOfDisplay (manager_xrandr->xdisplay,
 | 
			
		||||
			    DefaultScreen (manager_xrandr->xdisplay));
 | 
			
		||||
  /* This is updated because we called RRUpdateConfiguration below */
 | 
			
		||||
  manager->screen_width = WidthOfScreen (screen);
 | 
			
		||||
  manager->screen_height = HeightOfScreen (screen);
 | 
			
		||||
 | 
			
		||||
  resources = XRRGetScreenResourcesCurrent (manager_xrandr->xdisplay,
 | 
			
		||||
					    DefaultRootWindow (manager_xrandr->xdisplay));
 | 
			
		||||
  if (!resources)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  manager_xrandr->resources = resources;
 | 
			
		||||
  manager_xrandr->time = resources->configTimestamp;
 | 
			
		||||
  manager->n_outputs = resources->noutput;
 | 
			
		||||
  manager->n_crtcs = resources->ncrtc;
 | 
			
		||||
  manager->n_modes = resources->nmode;
 | 
			
		||||
  manager->outputs = g_new0 (MetaOutput, manager->n_outputs);
 | 
			
		||||
  manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
 | 
			
		||||
  manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < (unsigned)resources->nmode; i++)
 | 
			
		||||
    {
 | 
			
		||||
      XRRModeInfo *xmode = &resources->modes[i];
 | 
			
		||||
      MetaMonitorMode *mode;
 | 
			
		||||
 | 
			
		||||
      mode = &manager->modes[i];
 | 
			
		||||
 | 
			
		||||
      mode->mode_id = xmode->id;
 | 
			
		||||
      mode->width = xmode->width;
 | 
			
		||||
      mode->height = xmode->height;
 | 
			
		||||
      mode->refresh_rate = (xmode->dotClock /
 | 
			
		||||
			    ((float)xmode->hTotal * xmode->vTotal));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < (unsigned)resources->ncrtc; i++)
 | 
			
		||||
    {
 | 
			
		||||
      XRRCrtcInfo *crtc;
 | 
			
		||||
      MetaCRTC *meta_crtc;
 | 
			
		||||
 | 
			
		||||
      crtc = XRRGetCrtcInfo (manager_xrandr->xdisplay, resources, resources->crtcs[i]);
 | 
			
		||||
 | 
			
		||||
      meta_crtc = &manager->crtcs[i];
 | 
			
		||||
 | 
			
		||||
      meta_crtc->crtc_id = resources->crtcs[i];
 | 
			
		||||
      meta_crtc->rect.x = crtc->x;
 | 
			
		||||
      meta_crtc->rect.y = crtc->y;
 | 
			
		||||
      meta_crtc->rect.width = crtc->width;
 | 
			
		||||
      meta_crtc->rect.height = crtc->height;
 | 
			
		||||
      meta_crtc->dirty = FALSE;
 | 
			
		||||
      meta_crtc->transform = wl_transform_from_xrandr (crtc->rotation);
 | 
			
		||||
      meta_crtc->all_transforms = wl_transform_from_xrandr_all (crtc->rotations);
 | 
			
		||||
 | 
			
		||||
      for (j = 0; j < (unsigned)resources->nmode; j++)
 | 
			
		||||
	{
 | 
			
		||||
	  if (resources->modes[j].id == crtc->mode)
 | 
			
		||||
	    {
 | 
			
		||||
	      meta_crtc->current_mode = &manager->modes[j];
 | 
			
		||||
	      break;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      XRRFreeCrtcInfo (crtc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  primary_output = XRRGetOutputPrimary (manager_xrandr->xdisplay,
 | 
			
		||||
					DefaultRootWindow (manager_xrandr->xdisplay));
 | 
			
		||||
 | 
			
		||||
  n_actual_outputs = 0;
 | 
			
		||||
  for (i = 0; i < (unsigned)resources->noutput; i++)
 | 
			
		||||
    {
 | 
			
		||||
      XRROutputInfo *output;
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
 | 
			
		||||
      output = XRRGetOutputInfo (manager_xrandr->xdisplay, resources, resources->outputs[i]);
 | 
			
		||||
 | 
			
		||||
      meta_output = &manager->outputs[n_actual_outputs];
 | 
			
		||||
 | 
			
		||||
      if (output->connection != RR_Disconnected)
 | 
			
		||||
	{
 | 
			
		||||
	  meta_output->output_id = resources->outputs[i];
 | 
			
		||||
	  meta_output->name = g_strdup (output->name);
 | 
			
		||||
	  meta_output->vendor = g_strdup ("unknown");
 | 
			
		||||
	  meta_output->product = g_strdup ("unknown");
 | 
			
		||||
	  meta_output->serial = g_strdup ("");
 | 
			
		||||
	  meta_output->width_mm = output->mm_width;
 | 
			
		||||
	  meta_output->height_mm = output->mm_height;
 | 
			
		||||
	  meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
 | 
			
		||||
 | 
			
		||||
	  meta_output->n_modes = output->nmode;
 | 
			
		||||
	  meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
 | 
			
		||||
	  for (j = 0; j < meta_output->n_modes; j++)
 | 
			
		||||
	    {
 | 
			
		||||
	      for (k = 0; k < manager->n_modes; k++)
 | 
			
		||||
		{
 | 
			
		||||
		  if (output->modes[j] == (XID)manager->modes[k].mode_id)
 | 
			
		||||
		    {
 | 
			
		||||
		      meta_output->modes[j] = &manager->modes[k];
 | 
			
		||||
		      break;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	  meta_output->preferred_mode = meta_output->modes[0];
 | 
			
		||||
 | 
			
		||||
	  meta_output->n_possible_crtcs = output->ncrtc;
 | 
			
		||||
	  meta_output->possible_crtcs = g_new0 (MetaCRTC *, meta_output->n_possible_crtcs);
 | 
			
		||||
	  for (j = 0; j < (unsigned)output->ncrtc; j++)
 | 
			
		||||
	    {
 | 
			
		||||
	      for (k = 0; k < manager->n_crtcs; k++)
 | 
			
		||||
		{
 | 
			
		||||
		  if ((XID)manager->crtcs[k].crtc_id == output->crtcs[j])
 | 
			
		||||
		    {
 | 
			
		||||
		      meta_output->possible_crtcs[j] = &manager->crtcs[k];
 | 
			
		||||
		      break;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	  meta_output->crtc = NULL;
 | 
			
		||||
	  for (j = 0; j < manager->n_crtcs; j++)
 | 
			
		||||
	    {
 | 
			
		||||
	      if ((XID)manager->crtcs[j].crtc_id == output->crtc)
 | 
			
		||||
		{
 | 
			
		||||
		  meta_output->crtc = &manager->crtcs[j];
 | 
			
		||||
		  break;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	  meta_output->n_possible_clones = output->nclone;
 | 
			
		||||
	  meta_output->possible_clones = g_new0 (MetaOutput *, meta_output->n_possible_clones);
 | 
			
		||||
	  /* We can build the list of clones now, because we don't have the list of outputs
 | 
			
		||||
	     yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them
 | 
			
		||||
	     in a second pass
 | 
			
		||||
	  */
 | 
			
		||||
	  for (j = 0; j < (unsigned)output->nclone; j++)
 | 
			
		||||
	    {
 | 
			
		||||
	      meta_output->possible_clones = GINT_TO_POINTER (output->clones[j]);
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	  meta_output->is_primary = ((XID)meta_output->output_id == primary_output);
 | 
			
		||||
	  meta_output->is_presentation = output_get_presentation_xrandr (manager_xrandr, meta_output);
 | 
			
		||||
	  output_get_backlight_limits_xrandr (manager_xrandr, meta_output);
 | 
			
		||||
 | 
			
		||||
	  if (!(meta_output->backlight_min == 0 && meta_output->backlight_max == 0))
 | 
			
		||||
	    meta_output->backlight = output_get_backlight_xrandr (manager_xrandr, meta_output);
 | 
			
		||||
	  else
 | 
			
		||||
	    meta_output->backlight = -1;
 | 
			
		||||
 | 
			
		||||
	  n_actual_outputs++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      XRRFreeOutputInfo (output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  manager->n_outputs = n_actual_outputs;
 | 
			
		||||
 | 
			
		||||
  /* Sort the outputs for easier handling in MetaMonitorConfig */
 | 
			
		||||
  qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
 | 
			
		||||
 | 
			
		||||
  /* Now fix the clones */
 | 
			
		||||
  for (i = 0; i < manager->n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
 | 
			
		||||
      meta_output = &manager->outputs[i];
 | 
			
		||||
 | 
			
		||||
      for (j = 0; j < meta_output->n_possible_clones; j++)
 | 
			
		||||
	{
 | 
			
		||||
	  RROutput clone = GPOINTER_TO_INT (meta_output->possible_clones[j]);
 | 
			
		||||
 | 
			
		||||
	  for (k = 0; k < manager->n_outputs; k++)
 | 
			
		||||
	    {
 | 
			
		||||
	      if (clone == (XID)manager->outputs[k].output_id)
 | 
			
		||||
		{
 | 
			
		||||
		  meta_output->possible_clones[j] = &manager->outputs[k];
 | 
			
		||||
		  break;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static guint8 *
 | 
			
		||||
get_edid_property (Display  *dpy,
 | 
			
		||||
                   RROutput  output,
 | 
			
		||||
                   Atom      atom,
 | 
			
		||||
                   gsize    *len)
 | 
			
		||||
{
 | 
			
		||||
  unsigned char *prop;
 | 
			
		||||
  int actual_format;
 | 
			
		||||
  unsigned long nitems, bytes_after;
 | 
			
		||||
  Atom actual_type;
 | 
			
		||||
  guint8 *result;
 | 
			
		||||
 | 
			
		||||
  XRRGetOutputProperty (dpy, output, atom,
 | 
			
		||||
                        0, 100, False, False,
 | 
			
		||||
                        AnyPropertyType,
 | 
			
		||||
                        &actual_type, &actual_format,
 | 
			
		||||
                        &nitems, &bytes_after, &prop);
 | 
			
		||||
 | 
			
		||||
  if (actual_type == XA_INTEGER && actual_format == 8)
 | 
			
		||||
    {
 | 
			
		||||
      result = g_memdup (prop, nitems);
 | 
			
		||||
      if (len)
 | 
			
		||||
        *len = nitems;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      result = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  XFree (prop);
 | 
			
		||||
    
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GBytes *
 | 
			
		||||
meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager,
 | 
			
		||||
                                       MetaOutput         *output)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  Atom edid_atom;
 | 
			
		||||
  guint8 *result;
 | 
			
		||||
  gsize len;
 | 
			
		||||
 | 
			
		||||
  edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE);
 | 
			
		||||
  result = get_edid_property (manager_xrandr->xdisplay, output->output_id, edid_atom, &len);
 | 
			
		||||
 | 
			
		||||
  if (!result)
 | 
			
		||||
    {
 | 
			
		||||
      edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE);
 | 
			
		||||
      result = get_edid_property (manager_xrandr->xdisplay, output->output_id, edid_atom, &len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!result)
 | 
			
		||||
    {
 | 
			
		||||
      edid_atom = XInternAtom (manager_xrandr->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE);
 | 
			
		||||
      result = get_edid_property (manager_xrandr->xdisplay, output->output_id, edid_atom, &len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (result)
 | 
			
		||||
    {
 | 
			
		||||
      if (len > 0 && len % 128 == 0)
 | 
			
		||||
        return g_bytes_new_take (result, len);
 | 
			
		||||
      else
 | 
			
		||||
        g_free (result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_set_power_save_mode (MetaMonitorManager *manager,
 | 
			
		||||
						 MetaPowerSave       mode)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  CARD16 state;
 | 
			
		||||
 | 
			
		||||
  switch (mode) {
 | 
			
		||||
  case META_POWER_SAVE_ON:
 | 
			
		||||
    state = DPMSModeOn;
 | 
			
		||||
    break;
 | 
			
		||||
  case META_POWER_SAVE_STANDBY:
 | 
			
		||||
    state = DPMSModeStandby;
 | 
			
		||||
    break;
 | 
			
		||||
  case META_POWER_SAVE_SUSPEND:
 | 
			
		||||
    state = DPMSModeSuspend;
 | 
			
		||||
    break;
 | 
			
		||||
  case META_POWER_SAVE_OFF:
 | 
			
		||||
    state = DPMSModeOff;
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (meta_get_display ());
 | 
			
		||||
  DPMSForceLevel (manager_xrandr->xdisplay, state);
 | 
			
		||||
  DPMSSetTimeouts (manager_xrandr->xdisplay, 0, 0, 0);
 | 
			
		||||
  meta_error_trap_pop (meta_get_display ());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Rotation
 | 
			
		||||
wl_transform_to_xrandr (enum wl_output_transform transform)
 | 
			
		||||
{
 | 
			
		||||
  switch (transform)
 | 
			
		||||
    {
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_NORMAL:
 | 
			
		||||
      return RR_Rotate_0;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_90:
 | 
			
		||||
      return RR_Rotate_90;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_180:
 | 
			
		||||
      return RR_Rotate_180;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_270:
 | 
			
		||||
      return RR_Rotate_270;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_FLIPPED:
 | 
			
		||||
      return RR_Reflect_X | RR_Rotate_0;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 | 
			
		||||
      return RR_Reflect_X | RR_Rotate_90;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_FLIPPED_180:
 | 
			
		||||
      return RR_Reflect_X | RR_Rotate_180;
 | 
			
		||||
    case WL_OUTPUT_TRANSFORM_FLIPPED_270:
 | 
			
		||||
      return RR_Reflect_X | RR_Rotate_270;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
                                MetaOutput               *output,
 | 
			
		||||
                                gboolean                  presentation)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
  int value = presentation;
 | 
			
		||||
 | 
			
		||||
  XRRChangeOutputProperty (manager_xrandr->xdisplay,
 | 
			
		||||
                           (XID)output->output_id,
 | 
			
		||||
                           display->atom__MUTTER_PRESENTATION_OUTPUT,
 | 
			
		||||
                           XA_CARDINAL, 32, PropModeReplace,
 | 
			
		||||
                           (unsigned char*) &value, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
						 MetaCRTCInfo       **crtcs,
 | 
			
		||||
						 unsigned int         n_crtcs,
 | 
			
		||||
						 MetaOutputInfo     **outputs,
 | 
			
		||||
						 unsigned int         n_outputs)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  unsigned i;
 | 
			
		||||
 | 
			
		||||
  meta_display_grab (meta_get_display ());
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCRTCInfo *crtc_info = crtcs[i];
 | 
			
		||||
      MetaCRTC *crtc = crtc_info->crtc;
 | 
			
		||||
      crtc->dirty = TRUE;
 | 
			
		||||
 | 
			
		||||
      if (crtc_info->mode == NULL)
 | 
			
		||||
        {
 | 
			
		||||
          XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                            manager_xrandr->resources,
 | 
			
		||||
                            (XID)crtc->crtc_id,
 | 
			
		||||
                            manager_xrandr->time,
 | 
			
		||||
                            0, 0,
 | 
			
		||||
                            None,
 | 
			
		||||
                            RR_Rotate_0,
 | 
			
		||||
                            NULL, 0);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          MetaMonitorMode *mode;
 | 
			
		||||
          XID *outputs;
 | 
			
		||||
          int j, n_outputs;
 | 
			
		||||
          Status ok;
 | 
			
		||||
 | 
			
		||||
          mode = crtc_info->mode;
 | 
			
		||||
 | 
			
		||||
          n_outputs = crtc_info->outputs->len;
 | 
			
		||||
          outputs = g_new (XID, n_outputs);
 | 
			
		||||
 | 
			
		||||
          for (j = 0; j < n_outputs; j++)
 | 
			
		||||
            outputs[j] = ((MetaOutput**)crtc_info->outputs->pdata)[j]->output_id;
 | 
			
		||||
 | 
			
		||||
          meta_error_trap_push (meta_get_display ());
 | 
			
		||||
          ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                                 manager_xrandr->resources,
 | 
			
		||||
                                 (XID)crtc->crtc_id,
 | 
			
		||||
                                 manager_xrandr->time,
 | 
			
		||||
                                 crtc_info->x, crtc_info->y,
 | 
			
		||||
                                 (XID)mode->mode_id,
 | 
			
		||||
                                 wl_transform_to_xrandr (crtc_info->transform),
 | 
			
		||||
                                 outputs, n_outputs);
 | 
			
		||||
          meta_error_trap_pop (meta_get_display ());
 | 
			
		||||
 | 
			
		||||
          if (ok != Success)
 | 
			
		||||
            meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n",
 | 
			
		||||
                          (unsigned)(crtc - manager->crtcs), (unsigned)(mode - manager->modes),
 | 
			
		||||
                          mode->width, mode->height, (float)mode->refresh_rate,
 | 
			
		||||
                          crtc_info->x, crtc_info->y, crtc_info->transform);
 | 
			
		||||
 | 
			
		||||
          g_free (outputs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaOutputInfo *output_info = outputs[i];
 | 
			
		||||
 | 
			
		||||
      if (output_info->is_primary)
 | 
			
		||||
        {
 | 
			
		||||
          XRRSetOutputPrimary (manager_xrandr->xdisplay,
 | 
			
		||||
                               DefaultRootWindow (manager_xrandr->xdisplay),
 | 
			
		||||
                               (XID)output_info->output->output_id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      output_set_presentation_xrandr (manager_xrandr,
 | 
			
		||||
                                      output_info->output,
 | 
			
		||||
                                      output_info->is_presentation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list */
 | 
			
		||||
  for (i = 0; i < manager->n_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaCRTC *crtc = &manager->crtcs[i];
 | 
			
		||||
 | 
			
		||||
      if (crtc->dirty)
 | 
			
		||||
        {
 | 
			
		||||
          crtc->dirty = FALSE;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
      if (crtc->current_mode == NULL)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      XRRSetCrtcConfig (manager_xrandr->xdisplay,
 | 
			
		||||
                        manager_xrandr->resources,
 | 
			
		||||
                        (XID)crtc->crtc_id,
 | 
			
		||||
                        manager_xrandr->time,
 | 
			
		||||
                        0, 0,
 | 
			
		||||
                        None,
 | 
			
		||||
                        RR_Rotate_0,
 | 
			
		||||
                        NULL, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_display_ungrab (meta_get_display ());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager,
 | 
			
		||||
					      MetaOutput         *output,
 | 
			
		||||
					      gint                value)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
  int hw_value;
 | 
			
		||||
 | 
			
		||||
  hw_value = round((double)value / 100.0 * output->backlight_max + output->backlight_min);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (display);
 | 
			
		||||
  XRRChangeOutputProperty (manager_xrandr->xdisplay,
 | 
			
		||||
                           (XID)output->output_id,
 | 
			
		||||
                           display->atom_BACKLIGHT,
 | 
			
		||||
                           XA_INTEGER, 32, PropModeReplace,
 | 
			
		||||
                           (unsigned char *) &hw_value, 1);
 | 
			
		||||
  meta_error_trap_pop (display);
 | 
			
		||||
 | 
			
		||||
  /* We're not selecting for property notifies, so update the value immediately */
 | 
			
		||||
  output->backlight = normalize_backlight (output, hw_value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_get_crtc_gamma (MetaMonitorManager  *manager,
 | 
			
		||||
					    MetaCRTC            *crtc,
 | 
			
		||||
					    gsize               *size,
 | 
			
		||||
					    unsigned short     **red,
 | 
			
		||||
					    unsigned short     **green,
 | 
			
		||||
					    unsigned short     **blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  XRRCrtcGamma *gamma;
 | 
			
		||||
 | 
			
		||||
  gamma = XRRGetCrtcGamma (manager_xrandr->xdisplay, (XID)crtc->crtc_id);
 | 
			
		||||
 | 
			
		||||
  *size = gamma->size;
 | 
			
		||||
  *red = g_memdup (gamma->red, sizeof (unsigned short) * gamma->size);
 | 
			
		||||
  *green = g_memdup (gamma->green, sizeof (unsigned short) * gamma->size);
 | 
			
		||||
  *blue = g_memdup (gamma->blue, sizeof (unsigned short) * gamma->size);
 | 
			
		||||
 | 
			
		||||
  XRRFreeGamma (gamma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
 | 
			
		||||
					    MetaCRTC           *crtc,
 | 
			
		||||
					    gsize               size,
 | 
			
		||||
					    unsigned short     *red,
 | 
			
		||||
					    unsigned short     *green,
 | 
			
		||||
					    unsigned short     *blue)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
  XRRCrtcGamma gamma;
 | 
			
		||||
 | 
			
		||||
  gamma.size = size;
 | 
			
		||||
  gamma.red = red;
 | 
			
		||||
  gamma.green = green;
 | 
			
		||||
  gamma.blue = blue;
 | 
			
		||||
 | 
			
		||||
  XRRSetCrtcGamma (manager_xrandr->xdisplay, (XID)crtc->crtc_id, &gamma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
 | 
			
		||||
					   XEvent             *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
 | 
			
		||||
 | 
			
		||||
  if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  XRRUpdateConfiguration (event);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
 | 
			
		||||
  manager_xrandr->xdisplay = display->xdisplay;
 | 
			
		||||
 | 
			
		||||
  if (!XRRQueryExtension (manager_xrandr->xdisplay,
 | 
			
		||||
			  &manager_xrandr->rr_event_base,
 | 
			
		||||
			  &manager_xrandr->rr_error_base))
 | 
			
		||||
    {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* We only use ScreenChangeNotify, but GDK uses the others,
 | 
			
		||||
	 and we don't want to step on its toes */
 | 
			
		||||
      XRRSelectInput (manager_xrandr->xdisplay,
 | 
			
		||||
		      DefaultRootWindow (manager_xrandr->xdisplay),
 | 
			
		||||
		      RRScreenChangeNotifyMask
 | 
			
		||||
		      | RRCrtcChangeNotifyMask
 | 
			
		||||
		      | RROutputPropertyNotifyMask);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object);
 | 
			
		||||
 | 
			
		||||
  if (manager_xrandr->resources)
 | 
			
		||||
    XRRFreeScreenResources (manager_xrandr->resources);
 | 
			
		||||
  manager_xrandr->resources = NULL;
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_monitor_manager_xrandr_finalize;
 | 
			
		||||
 | 
			
		||||
  manager_class->read_current = meta_monitor_manager_xrandr_read_current;
 | 
			
		||||
  manager_class->read_edid = meta_monitor_manager_xrandr_read_edid;
 | 
			
		||||
  manager_class->apply_configuration = meta_monitor_manager_xrandr_apply_configuration;
 | 
			
		||||
  manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode;
 | 
			
		||||
  manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight;
 | 
			
		||||
  manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma;
 | 
			
		||||
  manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma;
 | 
			
		||||
  manager_class->handle_xevent = meta_monitor_manager_xrandr_handle_xevent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1554
									
								
								src/core/monitor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1554
									
								
								src/core/monitor.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -46,8 +46,15 @@ print_version (const gchar    *option_name,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gchar *plugin = "default";
 | 
			
		||||
static gboolean opt_nested = FALSE;
 | 
			
		||||
 | 
			
		||||
GOptionEntry mutter_options[] = {
 | 
			
		||||
  {
 | 
			
		||||
    "nested", 0, 0, G_OPTION_ARG_NONE,
 | 
			
		||||
    &opt_nested,
 | 
			
		||||
    N_("Run nested as an application for testing"),
 | 
			
		||||
    NULL,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
 | 
			
		||||
    print_version,
 | 
			
		||||
@@ -77,6 +84,8 @@ main (int argc, char **argv)
 | 
			
		||||
      exit (1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_set_is_wayland_compositor (opt_nested);
 | 
			
		||||
 | 
			
		||||
  if (plugin)
 | 
			
		||||
    meta_plugin_manager_load (plugin);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,17 +38,7 @@
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#include "stack-tracker.h"
 | 
			
		||||
#include "ui.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaMonitorInfo MetaMonitorInfo;
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorInfo
 | 
			
		||||
{
 | 
			
		||||
  int number;
 | 
			
		||||
  MetaRectangle rect;
 | 
			
		||||
  gboolean is_primary;
 | 
			
		||||
  gboolean in_fullscreen;
 | 
			
		||||
  XID output; /* The primary or first output for this crtc, None if no xrandr */
 | 
			
		||||
};
 | 
			
		||||
#include "monitor-private.h"
 | 
			
		||||
 | 
			
		||||
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
 | 
			
		||||
                                       gpointer user_data);
 | 
			
		||||
@@ -93,6 +83,7 @@ struct _MetaScreen
 | 
			
		||||
  MetaStack *stack;
 | 
			
		||||
  MetaStackTracker *stack_tracker;
 | 
			
		||||
 | 
			
		||||
  MetaCursorTracker *cursor_tracker;
 | 
			
		||||
  MetaCursor current_cursor;
 | 
			
		||||
 | 
			
		||||
  Window flash_window;
 | 
			
		||||
@@ -100,10 +91,11 @@ struct _MetaScreen
 | 
			
		||||
  Window wm_sn_selection_window;
 | 
			
		||||
  Atom wm_sn_atom;
 | 
			
		||||
  guint32 wm_sn_timestamp;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  MetaMonitorInfo *monitor_infos;
 | 
			
		||||
  int primary_monitor_index;
 | 
			
		||||
  int n_monitor_infos;
 | 
			
		||||
  int primary_monitor_index;
 | 
			
		||||
  gboolean has_xinerama_indices;
 | 
			
		||||
 | 
			
		||||
  /* Cache the current monitor */
 | 
			
		||||
  int last_monitor_index;
 | 
			
		||||
@@ -231,10 +223,6 @@ void meta_screen_calc_workspace_layout (MetaScreen          *screen,
 | 
			
		||||
                                        MetaWorkspaceLayout *layout);
 | 
			
		||||
void meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout);
 | 
			
		||||
 | 
			
		||||
void meta_screen_resize (MetaScreen *screen,
 | 
			
		||||
                         int         width,
 | 
			
		||||
                         int         height);
 | 
			
		||||
 | 
			
		||||
void     meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
 | 
			
		||||
                                                              MetaWindow *keep);
 | 
			
		||||
 | 
			
		||||
@@ -257,4 +245,14 @@ void     meta_screen_workspace_switched (MetaScreen         *screen,
 | 
			
		||||
 | 
			
		||||
void meta_screen_set_active_workspace_hint (MetaScreen *screen);
 | 
			
		||||
 | 
			
		||||
Window   meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
 | 
			
		||||
 | 
			
		||||
int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
 | 
			
		||||
                                                 int         index);
 | 
			
		||||
int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
 | 
			
		||||
                                                 int         index);
 | 
			
		||||
 | 
			
		||||
gboolean meta_screen_handle_xevent (MetaScreen *screen,
 | 
			
		||||
                                    XEvent     *xevent);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -45,13 +45,14 @@
 | 
			
		||||
#include <meta/compositor.h>
 | 
			
		||||
#include "mutter-enum-types.h"
 | 
			
		||||
#include "core.h"
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "meta-cursor-tracker-private.h"
 | 
			
		||||
#include "meta-idle-monitor-private.h"
 | 
			
		||||
 | 
			
		||||
#include <X11/extensions/Xinerama.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RANDR
 | 
			
		||||
#include <X11/extensions/Xrandr.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <X11/Xatom.h>
 | 
			
		||||
#include <locale.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@@ -76,6 +77,9 @@ static void meta_screen_sn_event   (SnMonitorEvent *event,
 | 
			
		||||
                                    void           *user_data);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void on_monitors_changed (MetaMonitorManager *manager,
 | 
			
		||||
                                 MetaScreen         *screen);
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  PROP_N_WORKSPACES = 1,
 | 
			
		||||
@@ -350,250 +354,93 @@ set_wm_icon_size_hint (MetaScreen *screen)
 | 
			
		||||
#undef N_VALS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The list of monitors reported by the windowing system might include
 | 
			
		||||
 * mirrored monitors with identical bounds. Since mirrored monitors
 | 
			
		||||
 * shouldn't be treated as separate monitors for most purposes, we
 | 
			
		||||
 * filter them out here. (We ignore the possibility of partially
 | 
			
		||||
 * overlapping monitors because they are rare and it's hard to come
 | 
			
		||||
 * up with any sensible interpretation.)
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
filter_mirrored_monitors (MetaScreen *screen)
 | 
			
		||||
meta_screen_ensure_xinerama_indices (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  int i, j;
 | 
			
		||||
  XineramaScreenInfo *infos;
 | 
			
		||||
  int n_infos, i, j;
 | 
			
		||||
 | 
			
		||||
  /* Currently always true and simplifies things */
 | 
			
		||||
  g_assert (screen->primary_monitor_index == 0);
 | 
			
		||||
  if (screen->has_xinerama_indices)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (i = 1; i < screen->n_monitor_infos; i++)
 | 
			
		||||
  screen->has_xinerama_indices = TRUE;
 | 
			
		||||
 | 
			
		||||
  if (!XineramaIsActive (screen->display->xdisplay))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  infos = XineramaQueryScreens (screen->display->xdisplay, &n_infos);
 | 
			
		||||
  if (n_infos <= 0 || infos == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      /* In case we've filtered previous monitors */
 | 
			
		||||
      screen->monitor_infos[i].number = i;
 | 
			
		||||
      meta_XFree (infos);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      for (j = 0; j < i; j++)
 | 
			
		||||
  for (i = 0; i < screen->n_monitor_infos; ++i)
 | 
			
		||||
    {
 | 
			
		||||
      for (j = 0; j < n_infos; ++j)
 | 
			
		||||
        {
 | 
			
		||||
          if (meta_rectangle_equal (&screen->monitor_infos[i].rect,
 | 
			
		||||
                                    &screen->monitor_infos[j].rect))
 | 
			
		||||
            {
 | 
			
		||||
              memmove (&screen->monitor_infos[i],
 | 
			
		||||
                       &screen->monitor_infos[i + 1],
 | 
			
		||||
                       (screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo));
 | 
			
		||||
              screen->n_monitor_infos--;
 | 
			
		||||
              i--;
 | 
			
		||||
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
          if (screen->monitor_infos[i].rect.x == infos[j].x_org &&
 | 
			
		||||
	      screen->monitor_infos[i].rect.y == infos[j].y_org &&
 | 
			
		||||
	      screen->monitor_infos[i].rect.width == infos[j].width &&
 | 
			
		||||
	      screen->monitor_infos[i].rect.height == infos[j].height)
 | 
			
		||||
            screen->monitor_infos[i].xinerama_index = j;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_XFree (infos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RANDR
 | 
			
		||||
static MetaMonitorInfo *
 | 
			
		||||
find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h)
 | 
			
		||||
int
 | 
			
		||||
meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
 | 
			
		||||
                                             int         index)
 | 
			
		||||
{
 | 
			
		||||
  meta_screen_ensure_xinerama_indices (screen);
 | 
			
		||||
 | 
			
		||||
  return screen->monitor_infos[index].xinerama_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
 | 
			
		||||
                                             int         index)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorInfo *info;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  meta_screen_ensure_xinerama_indices (screen);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < screen->n_monitor_infos; i++)
 | 
			
		||||
    {
 | 
			
		||||
      info = &screen->monitor_infos[i];
 | 
			
		||||
      if (x == info->rect.x &&
 | 
			
		||||
          y == info->rect.y &&
 | 
			
		||||
          w == info->rect.width &&
 | 
			
		||||
          h == info->rect.height)
 | 
			
		||||
        return info;
 | 
			
		||||
    }
 | 
			
		||||
  return NULL;
 | 
			
		||||
    if (screen->monitor_infos[i].xinerama_index == index)
 | 
			
		||||
      return i;
 | 
			
		||||
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
 | 
			
		||||
 * outputs the "main". This is the one we consider "owning" the windows, so if
 | 
			
		||||
 * the mirroring is changed to a dual monitor setup then the windows are moved to the
 | 
			
		||||
 * crtc that now has that main output. If one of the outputs is the primary that is
 | 
			
		||||
 * always the main, otherwise we just use the first.
 | 
			
		||||
 */
 | 
			
		||||
static XID
 | 
			
		||||
find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc)
 | 
			
		||||
{
 | 
			
		||||
  XRROutputInfo *output;
 | 
			
		||||
  RROutput primary_output;
 | 
			
		||||
  int i;
 | 
			
		||||
  XID res;
 | 
			
		||||
 | 
			
		||||
  primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot);
 | 
			
		||||
 | 
			
		||||
  res = None;
 | 
			
		||||
  for (i = 0; i < crtc->noutput; i++)
 | 
			
		||||
    {
 | 
			
		||||
      output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]);
 | 
			
		||||
      if (output->connection != RR_Disconnected &&
 | 
			
		||||
          (res == None || crtc->outputs[i] == primary_output))
 | 
			
		||||
        res = crtc->outputs[i];
 | 
			
		||||
      XRRFreeOutputInfo (output);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
reload_monitor_infos (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  GList *tmp;
 | 
			
		||||
  MetaMonitorManager *manager;
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    GList *tmp;
 | 
			
		||||
  tmp = screen->workspaces;
 | 
			
		||||
  while (tmp != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWorkspace *space = tmp->data;
 | 
			
		||||
 | 
			
		||||
    tmp = screen->workspaces;
 | 
			
		||||
    while (tmp != NULL)
 | 
			
		||||
      {
 | 
			
		||||
        MetaWorkspace *space = tmp->data;
 | 
			
		||||
      meta_workspace_invalidate_work_area (space);
 | 
			
		||||
      
 | 
			
		||||
      tmp = tmp->next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        meta_workspace_invalidate_work_area (space);
 | 
			
		||||
        
 | 
			
		||||
        tmp = tmp->next;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  /* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
 | 
			
		||||
 | 
			
		||||
  display = screen->display;
 | 
			
		||||
 | 
			
		||||
  /* Any previous screen->monitor_infos is freed by the caller */
 | 
			
		||||
 | 
			
		||||
  screen->monitor_infos = NULL;
 | 
			
		||||
  screen->n_monitor_infos = 0;
 | 
			
		||||
  screen->last_monitor_index = 0;
 | 
			
		||||
 | 
			
		||||
  /* Xinerama doesn't have a concept of primary monitor, however XRandR
 | 
			
		||||
   * does. However, the XRandR xinerama compat code always sorts the
 | 
			
		||||
   * primary output first, so we rely on that here. We could use the
 | 
			
		||||
   * native XRandR calls instead of xinerama, but that would be
 | 
			
		||||
   * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as
 | 
			
		||||
   * that is defined in terms of xinerama monitor indexes.
 | 
			
		||||
   * So, since we don't need anything in xrandr except the primary
 | 
			
		||||
   * we can keep using xinerama and use the first monitor as the
 | 
			
		||||
   * primary.
 | 
			
		||||
   */
 | 
			
		||||
  screen->primary_monitor_index = 0;
 | 
			
		||||
 | 
			
		||||
  screen->has_xinerama_indices = FALSE;
 | 
			
		||||
  screen->display->monitor_cache_invalidated = TRUE;
 | 
			
		||||
 | 
			
		||||
  if (g_getenv ("MUTTER_DEBUG_XINERAMA"))
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_XINERAMA,
 | 
			
		||||
                  "Pretending a single monitor has two Xinerama screens\n");
 | 
			
		||||
  manager = meta_monitor_manager_get ();
 | 
			
		||||
 | 
			
		||||
      screen->monitor_infos = g_new0 (MetaMonitorInfo, 2);
 | 
			
		||||
      screen->n_monitor_infos = 2;
 | 
			
		||||
 | 
			
		||||
      screen->monitor_infos[0].number = 0;
 | 
			
		||||
      screen->monitor_infos[0].rect = screen->rect;
 | 
			
		||||
      screen->monitor_infos[0].rect.width = screen->rect.width / 2;
 | 
			
		||||
      screen->monitor_infos[0].in_fullscreen = -1;
 | 
			
		||||
 | 
			
		||||
      screen->monitor_infos[1].number = 1;
 | 
			
		||||
      screen->monitor_infos[1].rect = screen->rect;
 | 
			
		||||
      screen->monitor_infos[1].rect.x = screen->rect.width / 2;
 | 
			
		||||
      screen->monitor_infos[1].rect.width = screen->rect.width / 2;
 | 
			
		||||
      screen->monitor_infos[0].in_fullscreen = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (screen->n_monitor_infos == 0 &&
 | 
			
		||||
      XineramaIsActive (display->xdisplay))
 | 
			
		||||
    {
 | 
			
		||||
      XineramaScreenInfo *infos;
 | 
			
		||||
      int n_infos;
 | 
			
		||||
      int i;
 | 
			
		||||
      
 | 
			
		||||
      n_infos = 0;
 | 
			
		||||
      infos = XineramaQueryScreens (display->xdisplay, &n_infos);
 | 
			
		||||
 | 
			
		||||
      meta_topic (META_DEBUG_XINERAMA,
 | 
			
		||||
                  "Found %d Xinerama screens on display %s\n",
 | 
			
		||||
                  n_infos, display->name);
 | 
			
		||||
 | 
			
		||||
      if (n_infos > 0)
 | 
			
		||||
        {
 | 
			
		||||
          screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos);
 | 
			
		||||
          screen->n_monitor_infos = n_infos;
 | 
			
		||||
          
 | 
			
		||||
          i = 0;
 | 
			
		||||
          while (i < n_infos)
 | 
			
		||||
            {
 | 
			
		||||
              screen->monitor_infos[i].number = infos[i].screen_number;
 | 
			
		||||
              screen->monitor_infos[i].rect.x = infos[i].x_org;
 | 
			
		||||
              screen->monitor_infos[i].rect.y = infos[i].y_org;
 | 
			
		||||
              screen->monitor_infos[i].rect.width = infos[i].width;
 | 
			
		||||
              screen->monitor_infos[i].rect.height = infos[i].height;
 | 
			
		||||
              screen->monitor_infos[i].in_fullscreen = -1;
 | 
			
		||||
 | 
			
		||||
              meta_topic (META_DEBUG_XINERAMA,
 | 
			
		||||
                          "Monitor %d is %d,%d %d x %d\n",
 | 
			
		||||
                          screen->monitor_infos[i].number,
 | 
			
		||||
                          screen->monitor_infos[i].rect.x,
 | 
			
		||||
                          screen->monitor_infos[i].rect.y,
 | 
			
		||||
                          screen->monitor_infos[i].rect.width,
 | 
			
		||||
                          screen->monitor_infos[i].rect.height);
 | 
			
		||||
              
 | 
			
		||||
              ++i;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
      meta_XFree (infos);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_RANDR
 | 
			
		||||
      {
 | 
			
		||||
        XRRScreenResources *resources;
 | 
			
		||||
 | 
			
		||||
        resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot);
 | 
			
		||||
        if (resources)
 | 
			
		||||
          {
 | 
			
		||||
            for (i = 0; i < resources->ncrtc; i++)
 | 
			
		||||
              {
 | 
			
		||||
                XRRCrtcInfo *crtc;
 | 
			
		||||
                MetaMonitorInfo *info;
 | 
			
		||||
 | 
			
		||||
                crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]);
 | 
			
		||||
                info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height);
 | 
			
		||||
                if (info)
 | 
			
		||||
                  info->output = find_main_output_for_crtc (screen, resources, crtc);
 | 
			
		||||
 | 
			
		||||
                XRRFreeCrtcInfo (crtc);
 | 
			
		||||
              }
 | 
			
		||||
            XRRFreeScreenResources (resources);
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
  else if (screen->n_monitor_infos > 0)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_XINERAMA,
 | 
			
		||||
                  "No Xinerama extension or Xinerama inactive on display %s\n",
 | 
			
		||||
                  display->name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* If no Xinerama, fill in the single screen info so
 | 
			
		||||
   * we can use the field unconditionally
 | 
			
		||||
   */
 | 
			
		||||
  if (screen->n_monitor_infos == 0)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_XINERAMA,
 | 
			
		||||
                  "No Xinerama screens, using default screen info\n");
 | 
			
		||||
          
 | 
			
		||||
      screen->monitor_infos = g_new0 (MetaMonitorInfo, 1);
 | 
			
		||||
      screen->n_monitor_infos = 1;
 | 
			
		||||
          
 | 
			
		||||
      screen->monitor_infos[0].number = 0;
 | 
			
		||||
      screen->monitor_infos[0].rect = screen->rect;
 | 
			
		||||
      screen->monitor_infos[0].in_fullscreen = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  filter_mirrored_monitors (screen);
 | 
			
		||||
 | 
			
		||||
  screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE;
 | 
			
		||||
 | 
			
		||||
  g_assert (screen->n_monitor_infos > 0);
 | 
			
		||||
  g_assert (screen->monitor_infos != NULL);
 | 
			
		||||
  screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager,
 | 
			
		||||
                                                                  (unsigned*)&screen->n_monitor_infos);
 | 
			
		||||
  screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The guard window allows us to leave minimized windows mapped so
 | 
			
		||||
@@ -603,12 +450,13 @@ reload_monitor_infos (MetaScreen *screen)
 | 
			
		||||
 * should effectively be forwarded to events on the background actor,
 | 
			
		||||
 * providing that the scene graph is set up correctly.
 | 
			
		||||
 */
 | 
			
		||||
static Window
 | 
			
		||||
create_guard_window (Display *xdisplay, MetaScreen *screen)
 | 
			
		||||
Window
 | 
			
		||||
meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  XSetWindowAttributes attributes;
 | 
			
		||||
  Window guard_window;
 | 
			
		||||
  gulong create_serial;
 | 
			
		||||
  MetaStackWindow stack_window;
 | 
			
		||||
  
 | 
			
		||||
  attributes.event_mask = NoEventMask;
 | 
			
		||||
  attributes.override_redirect = True;
 | 
			
		||||
@@ -641,12 +489,14 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
 | 
			
		||||
    XISelectEvents (xdisplay, guard_window, &mask, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
  stack_window.x11.xwindow = guard_window;
 | 
			
		||||
  meta_stack_tracker_record_add (screen->stack_tracker,
 | 
			
		||||
                                 guard_window,
 | 
			
		||||
                                 &stack_window,
 | 
			
		||||
                                 create_serial);
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_record_lower (screen->stack_tracker,
 | 
			
		||||
                                   guard_window,
 | 
			
		||||
                                   &stack_window,
 | 
			
		||||
                                   XNextRequest (xdisplay));
 | 
			
		||||
  XLowerWindow (xdisplay, guard_window);
 | 
			
		||||
  XMapWindow (xdisplay, guard_window);
 | 
			
		||||
@@ -668,6 +518,7 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
  char buf[128];
 | 
			
		||||
  guint32 manager_timestamp;
 | 
			
		||||
  gulong current_workspace;
 | 
			
		||||
  MetaMonitorManager *manager;
 | 
			
		||||
  
 | 
			
		||||
  replace_current_wm = meta_get_replace_current_wm ();
 | 
			
		||||
  
 | 
			
		||||
@@ -826,8 +677,26 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
  screen->xscreen = ScreenOfDisplay (xdisplay, number);
 | 
			
		||||
  screen->xroot = xroot;
 | 
			
		||||
  screen->rect.x = screen->rect.y = 0;
 | 
			
		||||
  screen->rect.width = WidthOfScreen (screen->xscreen);
 | 
			
		||||
  screen->rect.height = HeightOfScreen (screen->xscreen);
 | 
			
		||||
  
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
#endif
 | 
			
		||||
    meta_monitor_manager_initialize ();
 | 
			
		||||
 | 
			
		||||
  manager = meta_monitor_manager_get ();
 | 
			
		||||
  g_signal_connect (manager, "monitors-changed",
 | 
			
		||||
                    G_CALLBACK (on_monitors_changed), screen);
 | 
			
		||||
 | 
			
		||||
  meta_monitor_manager_get_screen_size (manager,
 | 
			
		||||
                                        &screen->rect.width,
 | 
			
		||||
                                        &screen->rect.height);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (!meta_is_wayland_compositor ())
 | 
			
		||||
#endif
 | 
			
		||||
    meta_monitor_manager_init_dbus (manager, NULL, NULL);
 | 
			
		||||
  meta_idle_monitor_init_dbus ();
 | 
			
		||||
 | 
			
		||||
  screen->current_cursor = -1; /* invalid/unset */
 | 
			
		||||
  screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
 | 
			
		||||
  screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
 | 
			
		||||
@@ -852,12 +721,9 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
  screen->compositor_data = NULL;
 | 
			
		||||
  screen->guard_window = None;
 | 
			
		||||
 | 
			
		||||
  screen->monitor_infos = NULL;
 | 
			
		||||
  screen->n_monitor_infos = 0;
 | 
			
		||||
  screen->last_monitor_index = 0;  
 | 
			
		||||
  
 | 
			
		||||
  reload_monitor_infos (screen);
 | 
			
		||||
  
 | 
			
		||||
  meta_cursor_tracker_get_for_screen (screen);  
 | 
			
		||||
  meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
 | 
			
		||||
 | 
			
		||||
  /* Handle creating a no_focus_window for this screen */  
 | 
			
		||||
@@ -941,7 +807,7 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
 | 
			
		||||
                screen->number, screen->screen_name, screen->xroot);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  return screen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1082,8 +948,8 @@ meta_screen_manage_all_windows (MetaScreen *screen)
 | 
			
		||||
  meta_display_grab (screen->display);
 | 
			
		||||
 | 
			
		||||
  if (screen->guard_window == None)
 | 
			
		||||
    screen->guard_window = create_guard_window (screen->display->xdisplay,
 | 
			
		||||
                                                screen);
 | 
			
		||||
    screen->guard_window =
 | 
			
		||||
      meta_screen_create_guard_window (screen->display->xdisplay, screen);
 | 
			
		||||
 | 
			
		||||
  windows = list_windows (screen);
 | 
			
		||||
 | 
			
		||||
@@ -1613,29 +1479,18 @@ void
 | 
			
		||||
meta_screen_set_cursor (MetaScreen *screen,
 | 
			
		||||
                        MetaCursor  cursor)
 | 
			
		||||
{
 | 
			
		||||
  Cursor xcursor;
 | 
			
		||||
 | 
			
		||||
  if (cursor == screen->current_cursor)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  screen->current_cursor = cursor;
 | 
			
		||||
  
 | 
			
		||||
  xcursor = meta_display_create_x_cursor (screen->display, cursor);
 | 
			
		||||
  XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
 | 
			
		||||
  XFlush (screen->display->xdisplay);
 | 
			
		||||
  XFreeCursor (screen->display->xdisplay, xcursor);
 | 
			
		||||
  meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_screen_update_cursor (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  Cursor xcursor;
 | 
			
		||||
 | 
			
		||||
  xcursor = meta_display_create_x_cursor (screen->display, 
 | 
			
		||||
					  screen->current_cursor);
 | 
			
		||||
  XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
 | 
			
		||||
  XFlush (screen->display->xdisplay);
 | 
			
		||||
  XFreeCursor (screen->display->xdisplay, xcursor);
 | 
			
		||||
  meta_cursor_tracker_set_root_cursor (screen->cursor_tracker,
 | 
			
		||||
                                       screen->current_cursor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -1898,12 +1753,15 @@ meta_screen_tile_preview_update_timeout (gpointer data)
 | 
			
		||||
    {
 | 
			
		||||
      Window xwindow;
 | 
			
		||||
      gulong create_serial;
 | 
			
		||||
      MetaStackWindow stack_window;
 | 
			
		||||
 | 
			
		||||
      screen->tile_preview = meta_tile_preview_new (screen->number);
 | 
			
		||||
      xwindow = meta_tile_preview_get_xwindow (screen->tile_preview,
 | 
			
		||||
                                               &create_serial);
 | 
			
		||||
      stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
      stack_window.x11.xwindow = xwindow;
 | 
			
		||||
      meta_stack_tracker_record_add (screen->stack_tracker,
 | 
			
		||||
                                     xwindow,
 | 
			
		||||
                                     &stack_window,
 | 
			
		||||
                                     create_serial);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -2997,19 +2855,15 @@ meta_screen_resize_func (MetaScreen *screen,
 | 
			
		||||
  meta_window_recalc_features (window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_screen_resize (MetaScreen *screen,
 | 
			
		||||
                    int         width,
 | 
			
		||||
                    int         height)
 | 
			
		||||
static void
 | 
			
		||||
on_monitors_changed (MetaMonitorManager *manager,
 | 
			
		||||
                     MetaScreen         *screen)
 | 
			
		||||
{
 | 
			
		||||
  GSList *windows, *tmp;
 | 
			
		||||
  MetaMonitorInfo *old_monitor_infos;
 | 
			
		||||
  GSList *tmp, *windows;
 | 
			
		||||
 | 
			
		||||
  screen->rect.width = width;
 | 
			
		||||
  screen->rect.height = height;
 | 
			
		||||
 | 
			
		||||
  /* Save the old monitor infos, so they stay valid during the update */
 | 
			
		||||
  old_monitor_infos = screen->monitor_infos;
 | 
			
		||||
  meta_monitor_manager_get_screen_size (manager,
 | 
			
		||||
                                        &screen->rect.width,
 | 
			
		||||
                                        &screen->rect.height);
 | 
			
		||||
 | 
			
		||||
  reload_monitor_infos (screen);
 | 
			
		||||
  set_desktop_geometry_hint (screen);
 | 
			
		||||
@@ -3021,8 +2875,8 @@ meta_screen_resize (MetaScreen *screen,
 | 
			
		||||
 | 
			
		||||
      changes.x = 0;
 | 
			
		||||
      changes.y = 0;
 | 
			
		||||
      changes.width = width;
 | 
			
		||||
      changes.height = height;
 | 
			
		||||
      changes.width = screen->rect.width;
 | 
			
		||||
      changes.height = screen->rect.height;
 | 
			
		||||
 | 
			
		||||
      XConfigureWindow(screen->display->xdisplay,
 | 
			
		||||
                       screen->guard_window,
 | 
			
		||||
@@ -3030,9 +2884,9 @@ meta_screen_resize (MetaScreen *screen,
 | 
			
		||||
                       &changes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (screen->display->compositor)
 | 
			
		||||
    meta_compositor_sync_screen_size (screen->display->compositor,
 | 
			
		||||
				      screen, width, height);
 | 
			
		||||
  meta_compositor_sync_screen_size (screen->display->compositor,
 | 
			
		||||
                                    screen,
 | 
			
		||||
                                    screen->rect.width, screen->rect.height);
 | 
			
		||||
 | 
			
		||||
  /* Queue a resize on all the windows */
 | 
			
		||||
  meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
 | 
			
		||||
@@ -3048,7 +2902,6 @@ meta_screen_resize (MetaScreen *screen,
 | 
			
		||||
        meta_window_update_for_monitors_changed (window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (old_monitor_infos);
 | 
			
		||||
  g_slist_free (windows);
 | 
			
		||||
 | 
			
		||||
  meta_screen_queue_check_fullscreen (screen);
 | 
			
		||||
@@ -3844,3 +3697,13 @@ meta_screen_get_monitor_in_fullscreen (MetaScreen  *screen,
 | 
			
		||||
  /* We use -1 as a flag to mean "not known yet" for notification purposes */
 | 
			
		||||
  return screen->monitor_infos[monitor].in_fullscreen == TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_screen_handle_xevent (MetaScreen *screen,
 | 
			
		||||
                           XEvent     *xevent)
 | 
			
		||||
{
 | 
			
		||||
  if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent))
 | 
			
		||||
    return TRUE;
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -37,36 +37,55 @@
 | 
			
		||||
#define META_STACK_TRACKER_H
 | 
			
		||||
 | 
			
		||||
#include <meta/screen.h>
 | 
			
		||||
#include <meta/window.h>
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaStackTracker MetaStackTracker;
 | 
			
		||||
 | 
			
		||||
typedef union _MetaStackWindow
 | 
			
		||||
{
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaWindowClientType type;
 | 
			
		||||
  } any;
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaWindowClientType type;
 | 
			
		||||
    Window xwindow;
 | 
			
		||||
  } x11;
 | 
			
		||||
  struct {
 | 
			
		||||
    MetaWindowClientType type;
 | 
			
		||||
    MetaWindow *meta_window;
 | 
			
		||||
  } wayland;
 | 
			
		||||
} MetaStackWindow;
 | 
			
		||||
 | 
			
		||||
gboolean meta_stack_window_equal (const MetaStackWindow *a,
 | 
			
		||||
                                  const MetaStackWindow *b);
 | 
			
		||||
 | 
			
		||||
MetaStackTracker *meta_stack_tracker_new  (MetaScreen       *screen);
 | 
			
		||||
void              meta_stack_tracker_free (MetaStackTracker *tracker);
 | 
			
		||||
 | 
			
		||||
/* These functions are called when we make an X call that changes the
 | 
			
		||||
 * stacking order; this allows MetaStackTracker to predict stacking
 | 
			
		||||
 * order before it receives events back from the X server */
 | 
			
		||||
void meta_stack_tracker_record_add             (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_remove          (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
 | 
			
		||||
						Window           *windows,
 | 
			
		||||
						int               n_windows,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_raise_above     (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
						Window            sibling,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_lower_below    (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
						Window            sibling,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_lower           (MetaStackTracker *tracker,
 | 
			
		||||
						Window            window,
 | 
			
		||||
                                                gulong            serial);
 | 
			
		||||
void meta_stack_tracker_record_add             (MetaStackTracker      *tracker,
 | 
			
		||||
                                                const MetaStackWindow *window,
 | 
			
		||||
                                                gulong                 serial);
 | 
			
		||||
void meta_stack_tracker_record_remove          (MetaStackTracker      *tracker,
 | 
			
		||||
                                                const MetaStackWindow *window,
 | 
			
		||||
                                                gulong                 serial);
 | 
			
		||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker      *tracker,
 | 
			
		||||
                                                const MetaStackWindow *windows,
 | 
			
		||||
						int                    n_windows,
 | 
			
		||||
                                                gulong                 serial);
 | 
			
		||||
void meta_stack_tracker_record_raise_above     (MetaStackTracker      *tracker,
 | 
			
		||||
                                                const MetaStackWindow *window,
 | 
			
		||||
                                                const MetaStackWindow *sibling,
 | 
			
		||||
                                                gulong                 serial);
 | 
			
		||||
void meta_stack_tracker_record_lower_below    (MetaStackTracker       *tracker,
 | 
			
		||||
                                               const MetaStackWindow  *window,
 | 
			
		||||
                                               const MetaStackWindow  *sibling,
 | 
			
		||||
                                               gulong                  serial);
 | 
			
		||||
void meta_stack_tracker_record_lower           (MetaStackTracker      *tracker,
 | 
			
		||||
                                                const MetaStackWindow *window,
 | 
			
		||||
                                                gulong                 serial);
 | 
			
		||||
 | 
			
		||||
/* These functions are used to update the stack when we get events
 | 
			
		||||
 * reflecting changes to the stacking order */
 | 
			
		||||
@@ -79,9 +98,9 @@ void meta_stack_tracker_reparent_event  (MetaStackTracker    *tracker,
 | 
			
		||||
void meta_stack_tracker_configure_event (MetaStackTracker    *tracker,
 | 
			
		||||
					 XConfigureEvent     *event);
 | 
			
		||||
 | 
			
		||||
void meta_stack_tracker_get_stack  (MetaStackTracker  *tracker,
 | 
			
		||||
                                    Window           **windows,
 | 
			
		||||
                                    int               *n_windows);
 | 
			
		||||
void meta_stack_tracker_get_stack  (MetaStackTracker      *tracker,
 | 
			
		||||
                                    MetaStackWindow      **windows,
 | 
			
		||||
                                    int                   *n_entries);
 | 
			
		||||
 | 
			
		||||
void meta_stack_tracker_sync_stack       (MetaStackTracker *tracker);
 | 
			
		||||
void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										534
									
								
								src/core/stack.c
									
									
									
									
									
								
							
							
						
						
									
										534
									
								
								src/core/stack.c
									
									
									
									
									
								
							@@ -52,7 +52,7 @@
 | 
			
		||||
 | 
			
		||||
#define WINDOW_IN_STACK(w) (w->stack_position >= 0)
 | 
			
		||||
 | 
			
		||||
static void stack_sync_to_server (MetaStack *stack);
 | 
			
		||||
static void stack_sync_to_xserver (MetaStack *stack);
 | 
			
		||||
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
 | 
			
		||||
                                                    int         position);
 | 
			
		||||
static void stack_do_window_deletions (MetaStack *stack);
 | 
			
		||||
@@ -71,14 +71,14 @@ meta_stack_new (MetaScreen *screen)
 | 
			
		||||
  stack = g_new (MetaStack, 1);
 | 
			
		||||
 | 
			
		||||
  stack->screen = screen;
 | 
			
		||||
  stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
  stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
 | 
			
		||||
  stack->sorted = NULL;
 | 
			
		||||
  stack->added = NULL;
 | 
			
		||||
  stack->removed = NULL;
 | 
			
		||||
 | 
			
		||||
  stack->freeze_count = 0;
 | 
			
		||||
  stack->last_root_children_stacked = NULL;
 | 
			
		||||
  stack->last_all_root_children_stacked = NULL;
 | 
			
		||||
 | 
			
		||||
  stack->n_positions = 0;
 | 
			
		||||
 | 
			
		||||
@@ -89,17 +89,34 @@ meta_stack_new (MetaScreen *screen)
 | 
			
		||||
  return stack;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
free_last_all_root_children_stacked_cache (MetaStack *stack)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < stack->last_all_root_children_stacked->len; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackWindow *window = &g_array_index (stack->last_all_root_children_stacked, MetaStackWindow, i);
 | 
			
		||||
      if (window->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND)
 | 
			
		||||
        g_object_remove_weak_pointer (G_OBJECT (window->wayland.meta_window),
 | 
			
		||||
                                      (gpointer *)&window->wayland.meta_window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_array_free (stack->last_all_root_children_stacked, TRUE);
 | 
			
		||||
  stack->last_all_root_children_stacked = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_stack_free (MetaStack *stack)
 | 
			
		||||
{
 | 
			
		||||
  g_array_free (stack->windows, TRUE);
 | 
			
		||||
  g_array_free (stack->xwindows, TRUE);
 | 
			
		||||
 | 
			
		||||
  g_list_free (stack->sorted);
 | 
			
		||||
  g_list_free (stack->added);
 | 
			
		||||
  g_list_free (stack->removed);
 | 
			
		||||
 | 
			
		||||
  if (stack->last_root_children_stacked)
 | 
			
		||||
    g_array_free (stack->last_root_children_stacked, TRUE);
 | 
			
		||||
  if (stack->last_all_root_children_stacked)
 | 
			
		||||
    free_last_all_root_children_stacked_cache (stack);
 | 
			
		||||
  
 | 
			
		||||
  g_free (stack);
 | 
			
		||||
}
 | 
			
		||||
@@ -121,7 +138,7 @@ meta_stack_add (MetaStack  *stack,
 | 
			
		||||
              "Window %s has stack_position initialized to %d\n",
 | 
			
		||||
              window->desc, window->stack_position);
 | 
			
		||||
  
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -157,7 +174,7 @@ meta_stack_remove (MetaStack  *stack,
 | 
			
		||||
    stack->removed = g_list_prepend (stack->removed,
 | 
			
		||||
                                     GUINT_TO_POINTER (window->frame->xwindow));
 | 
			
		||||
  
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -167,7 +184,7 @@ meta_stack_update_layer (MetaStack  *stack,
 | 
			
		||||
{
 | 
			
		||||
  stack->need_relayer = TRUE;
 | 
			
		||||
  
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -177,7 +194,7 @@ meta_stack_update_transient (MetaStack  *stack,
 | 
			
		||||
{
 | 
			
		||||
  stack->need_constrain = TRUE;
 | 
			
		||||
  
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -206,7 +223,7 @@ meta_stack_raise (MetaStack  *stack,
 | 
			
		||||
 | 
			
		||||
  meta_window_set_stack_position_no_sync (window, max_stack_position);
 | 
			
		||||
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -234,7 +251,7 @@ meta_stack_lower (MetaStack  *stack,
 | 
			
		||||
 | 
			
		||||
  meta_window_set_stack_position_no_sync (window, min_stack_position);
 | 
			
		||||
  
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -250,7 +267,7 @@ meta_stack_thaw (MetaStack *stack)
 | 
			
		||||
  g_return_if_fail (stack->freeze_count > 0);
 | 
			
		||||
  
 | 
			
		||||
  stack->freeze_count -= 1;
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -829,7 +846,7 @@ stack_do_window_deletions (MetaStack *stack)
 | 
			
		||||
      /* We go from the end figuring removals are more
 | 
			
		||||
       * likely to be recent.
 | 
			
		||||
       */
 | 
			
		||||
      i = stack->windows->len;
 | 
			
		||||
      i = stack->xwindows->len;
 | 
			
		||||
      while (i > 0)
 | 
			
		||||
        {
 | 
			
		||||
          --i;
 | 
			
		||||
@@ -840,9 +857,9 @@ stack_do_window_deletions (MetaStack *stack)
 | 
			
		||||
           * both the window->xwindow and window->frame->xwindow
 | 
			
		||||
           * in the removal list.
 | 
			
		||||
           */
 | 
			
		||||
          if (xwindow == g_array_index (stack->windows, Window, i))
 | 
			
		||||
          if (xwindow == g_array_index (stack->xwindows, Window, i))
 | 
			
		||||
            {
 | 
			
		||||
              g_array_remove_index (stack->windows, i);
 | 
			
		||||
              g_array_remove_index (stack->xwindows, i);
 | 
			
		||||
              goto next;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -871,10 +888,10 @@ stack_do_window_additions (MetaStack *stack)
 | 
			
		||||
                  "Adding %d windows to sorted list\n",
 | 
			
		||||
                  n_added);
 | 
			
		||||
      
 | 
			
		||||
      old_size = stack->windows->len;
 | 
			
		||||
      g_array_set_size (stack->windows, old_size + n_added);
 | 
			
		||||
      old_size = stack->xwindows->len;
 | 
			
		||||
      g_array_set_size (stack->xwindows, old_size + n_added);
 | 
			
		||||
      
 | 
			
		||||
      end = &g_array_index (stack->windows, Window, old_size);
 | 
			
		||||
      end = &g_array_index (stack->xwindows, Window, old_size);
 | 
			
		||||
 | 
			
		||||
      /* stack->added has the most recent additions at the
 | 
			
		||||
       * front of the list, so we need to reverse it
 | 
			
		||||
@@ -1029,6 +1046,102 @@ stack_ensure_sorted (MetaStack *stack)
 | 
			
		||||
  stack_do_resort (stack);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaStackWindow *
 | 
			
		||||
find_top_most_managed_window (MetaScreen *screen,
 | 
			
		||||
                              const MetaStackWindow *ignore)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackTracker *stack_tracker = screen->stack_tracker;
 | 
			
		||||
  MetaStackWindow *windows;
 | 
			
		||||
  int n_windows;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_get_stack (stack_tracker,
 | 
			
		||||
                                &windows, &n_windows);
 | 
			
		||||
 | 
			
		||||
  /* Children are in order from bottom to top. We want to
 | 
			
		||||
   * find the topmost managed child, then configure
 | 
			
		||||
   * our window to be above it.
 | 
			
		||||
   */
 | 
			
		||||
  for (i = n_windows -1; i >= 0; i--)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackWindow *other_window = &windows[i];
 | 
			
		||||
 | 
			
		||||
      if (other_window->any.type == ignore->any.type &&
 | 
			
		||||
          ((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
 | 
			
		||||
            other_window->x11.xwindow == ignore->x11.xwindow) ||
 | 
			
		||||
           other_window->wayland.meta_window == ignore->wayland.meta_window))
 | 
			
		||||
        {
 | 
			
		||||
          /* Do nothing. This means we're already the topmost managed
 | 
			
		||||
           * window, but it DOES NOT mean we are already just above
 | 
			
		||||
           * the topmost managed window. This is important because if
 | 
			
		||||
           * an override redirect window is up, and we map a new
 | 
			
		||||
           * managed window, the new window is probably above the old
 | 
			
		||||
           * popup by default, and we want to push it below that
 | 
			
		||||
           * popup. So keep looking for a sibling managed window
 | 
			
		||||
           * to be moved below.
 | 
			
		||||
           */
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
            {
 | 
			
		||||
              MetaWindow *other = meta_display_lookup_x_window (screen->display,
 | 
			
		||||
                                                                other_window->x11.xwindow);
 | 
			
		||||
 | 
			
		||||
              if (other != NULL && !other->override_redirect)
 | 
			
		||||
                return other_window;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              /* All wayland windows are currently considered "managed"
 | 
			
		||||
               * TODO: consider wayland pop-up windows like override
 | 
			
		||||
               * redirect windows here. */
 | 
			
		||||
              return other_window;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* When moving an X window we sometimes need an X based sibling.
 | 
			
		||||
 *
 | 
			
		||||
 * If the given sibling is X based this function returns it back
 | 
			
		||||
 * otherwise it searches downwards looking for the nearest X window.
 | 
			
		||||
 *
 | 
			
		||||
 * If no X based sibling could be found return NULL. */
 | 
			
		||||
static MetaStackWindow *
 | 
			
		||||
find_x11_sibling_downwards (MetaScreen *screen,
 | 
			
		||||
                            MetaStackWindow *sibling)
 | 
			
		||||
{
 | 
			
		||||
  MetaStackTracker *stack_tracker = screen->stack_tracker;
 | 
			
		||||
  MetaStackWindow *windows;
 | 
			
		||||
  int n_windows;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    return sibling;
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_get_stack (stack_tracker,
 | 
			
		||||
                                &windows, &n_windows);
 | 
			
		||||
 | 
			
		||||
  /* NB: Children are in order from bottom to top and we
 | 
			
		||||
   * want to search downwards for the nearest X window.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  for (i = n_windows - 1; i >= 0; i--)
 | 
			
		||||
    if (meta_stack_window_equal (&windows[i], sibling))
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
  for (; i >= 0; i--)
 | 
			
		||||
    {
 | 
			
		||||
      if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
        return &windows[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * raise_window_relative_to_managed_windows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -1053,84 +1166,74 @@ stack_ensure_sorted (MetaStack *stack)
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
raise_window_relative_to_managed_windows (MetaScreen *screen,
 | 
			
		||||
                                          Window      xwindow)
 | 
			
		||||
                                          const MetaStackWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  gulong serial = 0;
 | 
			
		||||
  MetaStackWindow *sibling;
 | 
			
		||||
 | 
			
		||||
  Window *children;
 | 
			
		||||
  int n_children;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_get_stack (screen->stack_tracker,
 | 
			
		||||
                                &children, &n_children);
 | 
			
		||||
 | 
			
		||||
  /* Children are in order from bottom to top. We want to
 | 
			
		||||
   * find the topmost managed child, then configure
 | 
			
		||||
   * our window to be above it.
 | 
			
		||||
   */
 | 
			
		||||
  i = n_children - 1;
 | 
			
		||||
  while (i >= 0)
 | 
			
		||||
  sibling = find_top_most_managed_window (screen, window);
 | 
			
		||||
  if (!sibling)
 | 
			
		||||
    {
 | 
			
		||||
      if (children[i] == xwindow)
 | 
			
		||||
      if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
        {
 | 
			
		||||
          /* Do nothing. This means we're already the topmost managed
 | 
			
		||||
           * window, but it DOES NOT mean we are already just above
 | 
			
		||||
           * the topmost managed window. This is important because if
 | 
			
		||||
           * an override redirect window is up, and we map a new
 | 
			
		||||
           * managed window, the new window is probably above the old
 | 
			
		||||
           * popup by default, and we want to push it below that
 | 
			
		||||
           * popup. So keep looking for a sibling managed window
 | 
			
		||||
           * to be moved below.
 | 
			
		||||
           */
 | 
			
		||||
          serial = XNextRequest (screen->display->xdisplay);
 | 
			
		||||
          meta_error_trap_push (screen->display);
 | 
			
		||||
          XLowerWindow (screen->display->xdisplay,
 | 
			
		||||
                        window->x11.xwindow);
 | 
			
		||||
          meta_error_trap_pop (screen->display);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          MetaWindow *other = meta_display_lookup_x_window (screen->display,
 | 
			
		||||
                                                            children[i]);
 | 
			
		||||
          if (other != NULL && !other->override_redirect)
 | 
			
		||||
            {
 | 
			
		||||
              XWindowChanges changes;
 | 
			
		||||
 | 
			
		||||
              /* children[i] is the topmost managed child */
 | 
			
		||||
      /* No sibling to use, just lower ourselves to the bottom
 | 
			
		||||
       * to be sure we're below any override redirect windows.
 | 
			
		||||
           */
 | 
			
		||||
      meta_stack_tracker_record_lower (screen->stack_tracker,
 | 
			
		||||
                                       window,
 | 
			
		||||
                                       serial);
 | 
			
		||||
      return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
  /* window is the topmost managed child */
 | 
			
		||||
              meta_topic (META_DEBUG_STACK,
 | 
			
		||||
                          "Moving 0x%lx above topmost managed child window 0x%lx\n",
 | 
			
		||||
                          xwindow, children[i]);
 | 
			
		||||
              window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0,
 | 
			
		||||
              sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0);
 | 
			
		||||
 | 
			
		||||
              changes.sibling = children[i];
 | 
			
		||||
  if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    {
 | 
			
		||||
      XWindowChanges changes;
 | 
			
		||||
      MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling);
 | 
			
		||||
      serial = XNextRequest (screen->display->xdisplay);
 | 
			
		||||
 | 
			
		||||
      if (x11_sibling)
 | 
			
		||||
        {
 | 
			
		||||
          changes.sibling = x11_sibling->x11.xwindow;
 | 
			
		||||
              changes.stack_mode = Above;
 | 
			
		||||
 | 
			
		||||
              meta_error_trap_push (screen->display);
 | 
			
		||||
              meta_stack_tracker_record_raise_above (screen->stack_tracker,
 | 
			
		||||
                                                     xwindow,
 | 
			
		||||
                                                     children[i],
 | 
			
		||||
                                                     XNextRequest (screen->display->xdisplay));
 | 
			
		||||
              XConfigureWindow (screen->display->xdisplay,
 | 
			
		||||
                                xwindow,
 | 
			
		||||
                            window->x11.xwindow,
 | 
			
		||||
                                CWSibling | CWStackMode,
 | 
			
		||||
                                &changes);
 | 
			
		||||
              meta_error_trap_pop (screen->display);
 | 
			
		||||
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      --i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (i < 0)
 | 
			
		||||
      else
 | 
			
		||||
    {
 | 
			
		||||
      /* No sibling to use, just lower ourselves to the bottom
 | 
			
		||||
       * to be sure we're below any override redirect windows.
 | 
			
		||||
       */
 | 
			
		||||
      meta_error_trap_push (screen->display);
 | 
			
		||||
      meta_stack_tracker_record_lower (screen->stack_tracker,
 | 
			
		||||
                                       xwindow,
 | 
			
		||||
                                       XNextRequest (screen->display->xdisplay));
 | 
			
		||||
      XLowerWindow (screen->display->xdisplay,
 | 
			
		||||
                    xwindow);
 | 
			
		||||
                        window->x11.xwindow);
 | 
			
		||||
      meta_error_trap_pop (screen->display);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  meta_stack_tracker_record_raise_above (screen->stack_tracker,
 | 
			
		||||
                                         window,
 | 
			
		||||
                                         sibling,
 | 
			
		||||
                                         serial);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * stack_sync_to_server:
 | 
			
		||||
 *
 | 
			
		||||
@@ -1145,13 +1248,16 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
 | 
			
		||||
 * job of computing the minimal set of stacking requests needed.
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
stack_sync_to_xserver (MetaStack *stack)
 | 
			
		||||
{
 | 
			
		||||
  GArray *stacked;
 | 
			
		||||
  GArray *root_children_stacked;
 | 
			
		||||
  GArray *x11_stacked;
 | 
			
		||||
  GArray *x11_root_children_stacked;
 | 
			
		||||
  GArray *all_root_children_stacked; /* wayland OR x11 */
 | 
			
		||||
  GList *tmp;
 | 
			
		||||
  GArray *all_hidden;
 | 
			
		||||
  GArray *x11_hidden;
 | 
			
		||||
  GArray *x11_hidden_stack_windows;
 | 
			
		||||
  int n_override_redirect = 0;
 | 
			
		||||
  MetaStackWindow guard_stack_window;
 | 
			
		||||
  
 | 
			
		||||
  /* Bail out if frozen */
 | 
			
		||||
  if (stack->freeze_count > 0)
 | 
			
		||||
@@ -1166,13 +1272,17 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
   * _NET hints, and "root_children_stacked" is in top-to-bottom
 | 
			
		||||
   * order for XRestackWindows()
 | 
			
		||||
   */
 | 
			
		||||
  stacked = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
  root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
  all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
  x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
 | 
			
		||||
  all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
 | 
			
		||||
  x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
 | 
			
		||||
  x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
 | 
			
		||||
  x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
 | 
			
		||||
 | 
			
		||||
  /* The screen guard window sits above all hidden windows and acts as
 | 
			
		||||
   * a barrier to input reaching these windows. */
 | 
			
		||||
  g_array_append_val (all_hidden, stack->screen->guard_window);
 | 
			
		||||
  g_array_append_val (x11_hidden, stack->screen->guard_window);
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "Top to bottom: ");
 | 
			
		||||
  meta_push_no_msg_prefix ();
 | 
			
		||||
@@ -1181,6 +1291,9 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindow *w = tmp->data;
 | 
			
		||||
      Window top_level_window;
 | 
			
		||||
      MetaStackWindow stack_window;
 | 
			
		||||
 | 
			
		||||
      stack_window.any.type = w->client_type;
 | 
			
		||||
      
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
 | 
			
		||||
		  w->layer, w->stack_position, w->desc);
 | 
			
		||||
@@ -1189,60 +1302,93 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
      if (w->override_redirect)
 | 
			
		||||
	n_override_redirect++;
 | 
			
		||||
      else
 | 
			
		||||
	g_array_prepend_val (stacked, w->xwindow);
 | 
			
		||||
	g_array_prepend_val (x11_stacked, w->xwindow);
 | 
			
		||||
      
 | 
			
		||||
      if (w->frame)
 | 
			
		||||
	top_level_window = w->frame->xwindow;
 | 
			
		||||
      else
 | 
			
		||||
	top_level_window = w->xwindow;
 | 
			
		||||
 | 
			
		||||
      if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
        stack_window.x11.xwindow = top_level_window;
 | 
			
		||||
      else
 | 
			
		||||
        stack_window.wayland.meta_window = w;
 | 
			
		||||
 | 
			
		||||
      /* We don't restack hidden windows along with the rest, though they are
 | 
			
		||||
       * reflected in the _NET hints. Hidden windows all get pushed below
 | 
			
		||||
       * the screens fullscreen guard_window. */
 | 
			
		||||
      if (w->hidden)
 | 
			
		||||
	{
 | 
			
		||||
	  g_array_append_val (all_hidden, top_level_window);
 | 
			
		||||
          if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
            {
 | 
			
		||||
              MetaStackWindow stack_window;
 | 
			
		||||
 | 
			
		||||
              stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
              stack_window.x11.xwindow = top_level_window;
 | 
			
		||||
 | 
			
		||||
              g_array_append_val (x11_hidden_stack_windows, stack_window);
 | 
			
		||||
              g_array_append_val (x11_hidden, top_level_window);
 | 
			
		||||
            }
 | 
			
		||||
	  continue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      g_array_append_val (all_root_children_stacked, stack_window);
 | 
			
		||||
 | 
			
		||||
      /* build XRestackWindows() array from top to bottom */
 | 
			
		||||
      g_array_append_val (root_children_stacked, top_level_window);
 | 
			
		||||
      if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
        g_array_append_val (x11_root_children_stacked, top_level_window);
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          MetaStackWindow *new;
 | 
			
		||||
 | 
			
		||||
          /* So we can determine later if a cached stack window is
 | 
			
		||||
           * stale because the corresponding window has been freed we
 | 
			
		||||
           * associate a weak pointer with the new window. */
 | 
			
		||||
          new = &g_array_index (all_root_children_stacked, MetaStackWindow, all_root_children_stacked->len - 1);
 | 
			
		||||
          g_object_add_weak_pointer (G_OBJECT (new->wayland.meta_window),
 | 
			
		||||
                                     (gpointer *)&new->wayland.meta_window);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "\n");
 | 
			
		||||
  meta_pop_no_msg_prefix ();
 | 
			
		||||
 | 
			
		||||
  /* All windows should be in some stacking order */
 | 
			
		||||
  if (stacked->len != stack->windows->len - n_override_redirect)
 | 
			
		||||
  /* All X windows should be in some stacking order */
 | 
			
		||||
  if (x11_stacked->len != stack->xwindows->len - n_override_redirect)
 | 
			
		||||
    meta_bug ("%u windows stacked, %u windows exist in stack\n",
 | 
			
		||||
              stacked->len, stack->windows->len);
 | 
			
		||||
              x11_stacked->len, stack->xwindows->len);
 | 
			
		||||
  
 | 
			
		||||
  /* Sync to server */
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
 | 
			
		||||
              root_children_stacked->len);
 | 
			
		||||
              all_root_children_stacked->len);
 | 
			
		||||
  
 | 
			
		||||
  meta_error_trap_push (stack->screen->display);
 | 
			
		||||
 | 
			
		||||
  if (stack->last_root_children_stacked == NULL)
 | 
			
		||||
  if (stack->last_all_root_children_stacked == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      /* Just impose our stack, we don't know the previous state.
 | 
			
		||||
       * This involves a ton of circulate requests and may flicker.
 | 
			
		||||
       */
 | 
			
		||||
      meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
 | 
			
		||||
 | 
			
		||||
      if (root_children_stacked->len > 0)
 | 
			
		||||
      if (all_root_children_stacked->len > 1)
 | 
			
		||||
        {
 | 
			
		||||
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                                     (Window *) root_children_stacked->data,
 | 
			
		||||
                                                     root_children_stacked->len,
 | 
			
		||||
                                                     XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
          gulong serial = 0;
 | 
			
		||||
          if (x11_root_children_stacked->len > 1)
 | 
			
		||||
            {
 | 
			
		||||
              serial = XNextRequest (stack->screen->display->xdisplay);
 | 
			
		||||
          XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
                           (Window *) root_children_stacked->data,
 | 
			
		||||
                           root_children_stacked->len);
 | 
			
		||||
                               (Window *) x11_root_children_stacked->data,
 | 
			
		||||
                               x11_root_children_stacked->len);
 | 
			
		||||
            }
 | 
			
		||||
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                                     (MetaStackWindow *) all_root_children_stacked->data,
 | 
			
		||||
                                                     all_root_children_stacked->len,
 | 
			
		||||
                                                     serial);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if (root_children_stacked->len > 0)
 | 
			
		||||
  else if (all_root_children_stacked->len > 0)
 | 
			
		||||
    {
 | 
			
		||||
      /* Try to do minimal window moves to get the stack in order */
 | 
			
		||||
      /* A point of note: these arrays include frames not client windows,
 | 
			
		||||
@@ -1250,28 +1396,34 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
       * was saved, then we may have inefficiency, but I don't think things
 | 
			
		||||
       * break...
 | 
			
		||||
       */
 | 
			
		||||
      const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
 | 
			
		||||
      const Window *new_stack = (Window *) root_children_stacked->data;
 | 
			
		||||
      const int old_len = stack->last_root_children_stacked->len;
 | 
			
		||||
      const int new_len = root_children_stacked->len;
 | 
			
		||||
      const Window *oldp = old_stack;
 | 
			
		||||
      const Window *newp = new_stack;
 | 
			
		||||
      const Window *old_end = old_stack + old_len;
 | 
			
		||||
      const Window *new_end = new_stack + new_len;
 | 
			
		||||
      Window last_window = None;
 | 
			
		||||
      
 | 
			
		||||
      const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data;
 | 
			
		||||
      const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data;
 | 
			
		||||
      const int old_len = stack->last_all_root_children_stacked->len;
 | 
			
		||||
      const int new_len = all_root_children_stacked->len;
 | 
			
		||||
      const MetaStackWindow *oldp = old_stack;
 | 
			
		||||
      const MetaStackWindow *newp = new_stack;
 | 
			
		||||
      const MetaStackWindow *old_end = old_stack + old_len;
 | 
			
		||||
      const MetaStackWindow *new_end = new_stack + new_len;
 | 
			
		||||
      Window last_xwindow = None;
 | 
			
		||||
      const MetaStackWindow *last_window = NULL;
 | 
			
		||||
 | 
			
		||||
      while (oldp != old_end &&
 | 
			
		||||
             newp != new_end)
 | 
			
		||||
        {
 | 
			
		||||
          if (*oldp == *newp)
 | 
			
		||||
          if (meta_stack_window_equal (oldp, newp))
 | 
			
		||||
            {
 | 
			
		||||
              /* Stacks are the same here, move on */
 | 
			
		||||
              ++oldp;
 | 
			
		||||
              last_window = *newp;
 | 
			
		||||
              if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
                last_xwindow = newp->x11.xwindow;
 | 
			
		||||
              last_window = newp;
 | 
			
		||||
              ++newp;
 | 
			
		||||
            }
 | 
			
		||||
          else if (meta_display_lookup_x_window (stack->screen->display,
 | 
			
		||||
                                                 *oldp) == NULL)
 | 
			
		||||
          else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
 | 
			
		||||
                    meta_display_lookup_x_window (stack->screen->display,
 | 
			
		||||
                                                  oldp->x11.xwindow) == NULL) ||
 | 
			
		||||
                   (oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
 | 
			
		||||
                    oldp->wayland.meta_window == NULL))
 | 
			
		||||
            {
 | 
			
		||||
              /* *oldp is no longer known to us (probably destroyed),
 | 
			
		||||
               * so we can just skip it
 | 
			
		||||
@@ -1280,75 +1432,161 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              /* Move *newp below last_window */
 | 
			
		||||
              if (last_window == None)
 | 
			
		||||
              /* Move *newp below the last_window */
 | 
			
		||||
              if (!last_window)
 | 
			
		||||
                {
 | 
			
		||||
                  meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);
 | 
			
		||||
                  meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n",
 | 
			
		||||
                              newp->x11.xwindow);
 | 
			
		||||
 | 
			
		||||
                  raise_window_relative_to_managed_windows (stack->screen,
 | 
			
		||||
                                                            *newp);
 | 
			
		||||
                  raise_window_relative_to_managed_windows (stack->screen, newp);
 | 
			
		||||
                }
 | 
			
		||||
              else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
 | 
			
		||||
                       last_xwindow == None)
 | 
			
		||||
                {
 | 
			
		||||
                  /* In this case we have an X window that we need to
 | 
			
		||||
                   * put below a wayland window and this is the
 | 
			
		||||
                   * topmost X window. */
 | 
			
		||||
                  
 | 
			
		||||
                  /* In X terms (because this is the topmost X window)
 | 
			
		||||
                   * we want to
 | 
			
		||||
                   * raise_window_relative_to_managed_windows() to
 | 
			
		||||
                   * ensure the X window is below override-redirect
 | 
			
		||||
                   * pop-up windows.
 | 
			
		||||
                   *
 | 
			
		||||
                   * In Wayland terms we just want to ensure
 | 
			
		||||
                   * newp is lowered below last_window (which
 | 
			
		||||
                   * notably doesn't require an X request because we
 | 
			
		||||
                   * know last_window isn't an X window).
 | 
			
		||||
                   */
 | 
			
		||||
 | 
			
		||||
                  raise_window_relative_to_managed_windows (stack->screen, newp);
 | 
			
		||||
 | 
			
		||||
                  meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
 | 
			
		||||
                                                         newp, last_window,
 | 
			
		||||
                                                         0); /* no x request serial */
 | 
			
		||||
                }
 | 
			
		||||
              else
 | 
			
		||||
                {
 | 
			
		||||
                  /* This means that if last_window is dead, but not
 | 
			
		||||
                  gulong serial = 0;
 | 
			
		||||
 | 
			
		||||
                  /* This means that if last_xwindow is dead, but not
 | 
			
		||||
                   * *newp, then we fail to restack *newp; but on
 | 
			
		||||
                   * unmanaging last_window, we'll fix it up.
 | 
			
		||||
                   * unmanaging last_xwindow, we'll fix it up.
 | 
			
		||||
                   */
 | 
			
		||||
                  
 | 
			
		||||
                  XWindowChanges changes;
 | 
			
		||||
                  meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
 | 
			
		||||
                              newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0,
 | 
			
		||||
                              last_xwindow);
 | 
			
		||||
 | 
			
		||||
                  changes.sibling = last_window;
 | 
			
		||||
                  if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
                    {
 | 
			
		||||
                  XWindowChanges changes;
 | 
			
		||||
                      serial = XNextRequest (stack->screen->display->xdisplay);
 | 
			
		||||
 | 
			
		||||
                      changes.sibling = last_xwindow;
 | 
			
		||||
                  changes.stack_mode = Below;
 | 
			
		||||
 | 
			
		||||
                  meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
 | 
			
		||||
                              *newp, last_window);
 | 
			
		||||
 | 
			
		||||
                  meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
 | 
			
		||||
                                                         *newp, last_window,
 | 
			
		||||
                                                         XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
                  XConfigureWindow (stack->screen->display->xdisplay,
 | 
			
		||||
                                    *newp,
 | 
			
		||||
                                        newp->x11.xwindow,
 | 
			
		||||
                                    CWSibling | CWStackMode,
 | 
			
		||||
                                    &changes);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              last_window = *newp;
 | 
			
		||||
                  meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
 | 
			
		||||
                                                         newp, last_window,
 | 
			
		||||
                                                         serial);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
                last_xwindow = newp->x11.xwindow;
 | 
			
		||||
              last_window = newp;
 | 
			
		||||
              ++newp;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (newp != new_end)
 | 
			
		||||
        {
 | 
			
		||||
          const MetaStackWindow *x_ref;
 | 
			
		||||
          unsigned long serial = 0;
 | 
			
		||||
 | 
			
		||||
          /* Restack remaining windows */
 | 
			
		||||
          meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
 | 
			
		||||
                        (int) (new_end - newp));
 | 
			
		||||
 | 
			
		||||
          /* rewind until we find the last stacked X window that we can use
 | 
			
		||||
           * as a reference point for re-stacking remaining X windows */
 | 
			
		||||
          if (newp != new_stack)
 | 
			
		||||
            for (x_ref = newp - 1;
 | 
			
		||||
                 x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
 | 
			
		||||
                 x_ref--)
 | 
			
		||||
              ;
 | 
			
		||||
          else
 | 
			
		||||
            x_ref = new_stack;
 | 
			
		||||
 | 
			
		||||
          /* If we didn't find an X window looking backwards then walk forwards
 | 
			
		||||
           * through the remaining windows to find the first remaining X window
 | 
			
		||||
           * instead. */
 | 
			
		||||
          if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
            {
 | 
			
		||||
              for (x_ref = newp;
 | 
			
		||||
                   x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
 | 
			
		||||
                   x_ref++)
 | 
			
		||||
                ;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          /* If there are any X windows remaining unstacked then restack them */
 | 
			
		||||
          if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
            {
 | 
			
		||||
              int i;
 | 
			
		||||
 | 
			
		||||
              for (i = x11_root_children_stacked->len - 1; i; i--)
 | 
			
		||||
                {
 | 
			
		||||
                  Window *reference = &g_array_index (x11_root_children_stacked, Window, i);
 | 
			
		||||
 | 
			
		||||
                  if (*reference == x_ref->x11.xwindow)
 | 
			
		||||
                    {
 | 
			
		||||
                      int n = x11_root_children_stacked->len - i;
 | 
			
		||||
 | 
			
		||||
                      /* There's no point restacking if there's only one X window */
 | 
			
		||||
                      if (n == 1)
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                      serial = XNextRequest (stack->screen->display->xdisplay);
 | 
			
		||||
                      XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
                                       reference, n);
 | 
			
		||||
                      break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          /* We need to include an already-stacked window
 | 
			
		||||
           * in the restack call, so we get in the proper position
 | 
			
		||||
           * with respect to it.
 | 
			
		||||
           */
 | 
			
		||||
          if (newp != new_stack)
 | 
			
		||||
            --newp;
 | 
			
		||||
            newp = MIN (newp - 1, x_ref);
 | 
			
		||||
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                                     (Window *) newp, new_end - newp,
 | 
			
		||||
                                                     XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
          XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
                           (Window *) newp, new_end - newp);
 | 
			
		||||
                                                     newp, new_end - newp,
 | 
			
		||||
                                                     serial);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Push hidden windows to the bottom of the stack under the guard window */
 | 
			
		||||
  /* Push hidden X windows to the bottom of the stack under the guard window */
 | 
			
		||||
  guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
 | 
			
		||||
  guard_stack_window.x11.xwindow = stack->screen->guard_window;
 | 
			
		||||
  meta_stack_tracker_record_lower (stack->screen->stack_tracker,
 | 
			
		||||
                                   stack->screen->guard_window,
 | 
			
		||||
                                   &guard_stack_window,
 | 
			
		||||
                                   XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
  XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
 | 
			
		||||
  meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
 | 
			
		||||
                                             (Window *)all_hidden->data,
 | 
			
		||||
                                             all_hidden->len,
 | 
			
		||||
                                             (MetaStackWindow *)x11_hidden_stack_windows->data,
 | 
			
		||||
                                             x11_hidden_stack_windows->len,
 | 
			
		||||
                                             XNextRequest (stack->screen->display->xdisplay));
 | 
			
		||||
  XRestackWindows (stack->screen->display->xdisplay,
 | 
			
		||||
		   (Window *)all_hidden->data,
 | 
			
		||||
		   all_hidden->len);
 | 
			
		||||
  g_array_free (all_hidden, TRUE);
 | 
			
		||||
		   (Window *)x11_hidden->data,
 | 
			
		||||
		   x11_hidden->len);
 | 
			
		||||
  g_array_free (x11_hidden, TRUE);
 | 
			
		||||
  g_array_free (x11_hidden_stack_windows, TRUE);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_pop (stack->screen->display);
 | 
			
		||||
  /* on error, a window was destroyed; it should eventually
 | 
			
		||||
@@ -1363,21 +1601,23 @@ stack_sync_to_server (MetaStack *stack)
 | 
			
		||||
                   stack->screen->display->atom__NET_CLIENT_LIST,
 | 
			
		||||
                   XA_WINDOW,
 | 
			
		||||
                   32, PropModeReplace,
 | 
			
		||||
                   (unsigned char *)stack->windows->data,
 | 
			
		||||
                   stack->windows->len);
 | 
			
		||||
                   (unsigned char *)stack->xwindows->data,
 | 
			
		||||
                   stack->xwindows->len);
 | 
			
		||||
  XChangeProperty (stack->screen->display->xdisplay,
 | 
			
		||||
                   stack->screen->xroot,
 | 
			
		||||
                   stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
 | 
			
		||||
                   XA_WINDOW,
 | 
			
		||||
                   32, PropModeReplace,
 | 
			
		||||
                   (unsigned char *)stacked->data,
 | 
			
		||||
                   stacked->len);
 | 
			
		||||
                   (unsigned char *)x11_stacked->data,
 | 
			
		||||
                   x11_stacked->len);
 | 
			
		||||
 | 
			
		||||
  g_array_free (stacked, TRUE);
 | 
			
		||||
  g_array_free (x11_stacked, TRUE);
 | 
			
		||||
 | 
			
		||||
  if (stack->last_root_children_stacked)
 | 
			
		||||
    g_array_free (stack->last_root_children_stacked, TRUE);
 | 
			
		||||
  stack->last_root_children_stacked = root_children_stacked;
 | 
			
		||||
  if (stack->last_all_root_children_stacked)
 | 
			
		||||
    free_last_all_root_children_stacked_cache (stack);
 | 
			
		||||
  stack->last_all_root_children_stacked = all_root_children_stacked;
 | 
			
		||||
 | 
			
		||||
  g_array_free (x11_root_children_stacked, TRUE);
 | 
			
		||||
 | 
			
		||||
  /* That was scary... */
 | 
			
		||||
}
 | 
			
		||||
@@ -1738,7 +1978,7 @@ meta_stack_set_positions (MetaStack *stack,
 | 
			
		||||
  meta_topic (META_DEBUG_STACK,
 | 
			
		||||
              "Reset the stack positions of (nearly) all windows\n");
 | 
			
		||||
 | 
			
		||||
  stack_sync_to_server (stack);
 | 
			
		||||
  stack_sync_to_xserver (stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (stack, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1801,7 +2041,7 @@ meta_window_set_stack_position (MetaWindow *window,
 | 
			
		||||
                                int         position)
 | 
			
		||||
{
 | 
			
		||||
  meta_window_set_stack_position_no_sync (window, position);
 | 
			
		||||
  stack_sync_to_server (window->screen->stack);
 | 
			
		||||
  stack_sync_to_xserver (window->screen->stack);
 | 
			
		||||
  meta_stack_update_window_tile_matches (window->screen->stack,
 | 
			
		||||
                                         window->screen->active_workspace);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ struct _MetaStack
 | 
			
		||||
   * A sequence of all the Windows (X handles, not MetaWindows) of the windows
 | 
			
		||||
   * we manage, sorted in order.  Suitable to be passed into _NET_CLIENT_LIST.
 | 
			
		||||
   */
 | 
			
		||||
  GArray *windows;
 | 
			
		||||
  GArray *xwindows;
 | 
			
		||||
 | 
			
		||||
  /** The MetaWindows of the windows we manage, sorted in order. */
 | 
			
		||||
  GList *sorted;
 | 
			
		||||
@@ -99,7 +99,7 @@ struct _MetaStack
 | 
			
		||||
   * The last-known stack of all windows, bottom to top.  We cache it here
 | 
			
		||||
   * so that subsequent times we'll be able to do incremental moves.
 | 
			
		||||
   */
 | 
			
		||||
  GArray *last_root_children_stacked;
 | 
			
		||||
  GArray *last_all_root_children_stacked;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Number of stack positions; same as the length of added, but
 | 
			
		||||
 
 | 
			
		||||
@@ -55,6 +55,7 @@ static gint verbose_topics = 0;
 | 
			
		||||
static gboolean is_debugging = FALSE;
 | 
			
		||||
static gboolean replace_current = FALSE;
 | 
			
		||||
static int no_prefix = 0;
 | 
			
		||||
static gboolean is_wayland_compositor = FALSE;
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_VERBOSE_MODE
 | 
			
		||||
static FILE* logfile = NULL;
 | 
			
		||||
@@ -194,6 +195,18 @@ meta_set_replace_current_wm (gboolean setting)
 | 
			
		||||
  replace_current = setting;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_is_wayland_compositor (void)
 | 
			
		||||
{
 | 
			
		||||
  return is_wayland_compositor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_set_is_wayland_compositor (gboolean value)
 | 
			
		||||
{
 | 
			
		||||
  is_wayland_compositor = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *
 | 
			
		||||
meta_g_utf8_strndup (const gchar *src,
 | 
			
		||||
                     gsize        n)
 | 
			
		||||
@@ -332,6 +345,8 @@ topic_name (MetaDebugTopic topic)
 | 
			
		||||
      return "COMPOSITOR";
 | 
			
		||||
    case META_DEBUG_EDGE_RESISTANCE:
 | 
			
		||||
      return "EDGE_RESISTANCE";
 | 
			
		||||
    case META_DEBUG_DBUS:
 | 
			
		||||
      return "DBUS";
 | 
			
		||||
    case META_DEBUG_VERBOSE:
 | 
			
		||||
      return "VERBOSE";
 | 
			
		||||
    }
 | 
			
		||||
@@ -637,8 +652,13 @@ meta_show_dialog (const char *type,
 | 
			
		||||
 | 
			
		||||
  append_argument (args, "zenity");
 | 
			
		||||
  append_argument (args, type);
 | 
			
		||||
  append_argument (args, "--display");
 | 
			
		||||
  append_argument (args, display);
 | 
			
		||||
 | 
			
		||||
  if (display)
 | 
			
		||||
    {
 | 
			
		||||
      append_argument (args, "--display");
 | 
			
		||||
      append_argument (args, display);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  append_argument (args, "--class");
 | 
			
		||||
  append_argument (args, "mutter-dialog");
 | 
			
		||||
  append_argument (args, "--title");
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,17 @@
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#include <cairo.h>
 | 
			
		||||
#include <gdk-pixbuf/gdk-pixbuf.h>
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* XXX: We should find a nicer approach to deal with the
 | 
			
		||||
 * circular dependency we have with the current headers
 | 
			
		||||
 * (meta-wayland-private.h which typedefs MetaWaylandSurface
 | 
			
		||||
 *  also includes window-private.h) */
 | 
			
		||||
#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
 | 
			
		||||
typedef struct _MetaWaylandSurface MetaWaylandSurface;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWindowQueue MetaWindowQueue;
 | 
			
		||||
 | 
			
		||||
@@ -69,6 +80,7 @@ typedef enum {
 | 
			
		||||
  _NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
 | 
			
		||||
} MetaBypassCompositorHintValue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct _MetaWindow
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
@@ -77,6 +89,10 @@ struct _MetaWindow
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
  const MetaMonitorInfo *monitor;
 | 
			
		||||
  MetaWorkspace *workspace;
 | 
			
		||||
  MetaWindowClientType client_type;
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
#endif
 | 
			
		||||
  Window xwindow;
 | 
			
		||||
  /* may be NULL! not all windows get decorated */
 | 
			
		||||
  MetaFrame *frame;
 | 
			
		||||
@@ -165,7 +181,7 @@ struct _MetaWindow
 | 
			
		||||
   * been overridden (via a client message), the window will cover the union of
 | 
			
		||||
   * these monitors.  If not, this is the single monitor which the window's
 | 
			
		||||
   * origin is on. */
 | 
			
		||||
  long fullscreen_monitors[4];
 | 
			
		||||
  gint fullscreen_monitors[4];
 | 
			
		||||
  
 | 
			
		||||
  /* Whether we're trying to constrain the window to be fully onscreen */
 | 
			
		||||
  guint require_fully_onscreen : 1;
 | 
			
		||||
@@ -325,8 +341,10 @@ struct _MetaWindow
 | 
			
		||||
  guint using_net_wm_icon_name         : 1; /* vs. plain wm_icon_name */
 | 
			
		||||
  guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
 | 
			
		||||
 | 
			
		||||
  /* has a shape mask */
 | 
			
		||||
  /* has a bounding shape mask */
 | 
			
		||||
  guint has_shape : 1;
 | 
			
		||||
  /* has an input shape mask */
 | 
			
		||||
  guint has_input_shape : 1;
 | 
			
		||||
 | 
			
		||||
  /* icon props have changed */
 | 
			
		||||
  guint need_reread_icon : 1;
 | 
			
		||||
@@ -490,6 +508,10 @@ MetaWindow* meta_window_new_with_attrs     (MetaDisplay       *display,
 | 
			
		||||
                                            gboolean           must_be_viewable,
 | 
			
		||||
                                            MetaCompEffect     effect,
 | 
			
		||||
                                            XWindowAttributes *attrs);
 | 
			
		||||
MetaWindow *meta_window_new_for_wayland    (MetaDisplay        *display,
 | 
			
		||||
                                            int                 width,
 | 
			
		||||
                                            int                 height,
 | 
			
		||||
                                            MetaWaylandSurface *surface);
 | 
			
		||||
void        meta_window_unmanage           (MetaWindow  *window,
 | 
			
		||||
                                            guint32      timestamp);
 | 
			
		||||
void        meta_window_calc_showing       (MetaWindow  *window);
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,10 @@
 | 
			
		||||
 | 
			
		||||
#include <X11/extensions/Xcomposite.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Windows that unmaximize to a size bigger than that fraction of the workarea
 | 
			
		||||
 * will be scaled down to that size (while maintaining aspect ratio).
 | 
			
		||||
 * Windows that cover an area greater then this size are automaximized on map.
 | 
			
		||||
@@ -713,10 +717,10 @@ meta_window_new (MetaDisplay *display,
 | 
			
		||||
 * Returns TRUE if window has been filtered out and should be ignored.
 | 
			
		||||
 */
 | 
			
		||||
static gboolean
 | 
			
		||||
maybe_filter_window (MetaDisplay       *display,
 | 
			
		||||
                     Window             xwindow,
 | 
			
		||||
                     gboolean           must_be_viewable,
 | 
			
		||||
                     XWindowAttributes *attrs)
 | 
			
		||||
maybe_filter_xwindow (MetaDisplay       *display,
 | 
			
		||||
                      Window             xwindow,
 | 
			
		||||
                      gboolean           must_be_viewable,
 | 
			
		||||
                      XWindowAttributes *attrs)
 | 
			
		||||
{
 | 
			
		||||
  static char **filter_wm_classes = NULL;
 | 
			
		||||
  static gboolean initialized = FALSE;
 | 
			
		||||
@@ -812,80 +816,25 @@ meta_window_should_attach_to_parent (MetaWindow *window)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWindow*
 | 
			
		||||
meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
                            Window             xwindow,
 | 
			
		||||
                            gboolean           must_be_viewable,
 | 
			
		||||
                            MetaCompEffect     effect,
 | 
			
		||||
                            XWindowAttributes *attrs)
 | 
			
		||||
static MetaWindow*
 | 
			
		||||
meta_window_new_shared (MetaDisplay         *display,
 | 
			
		||||
                        MetaScreen          *screen,
 | 
			
		||||
                        MetaWindowClientType client_type,
 | 
			
		||||
                        MetaWaylandSurface  *surface,
 | 
			
		||||
                        Window               xwindow,
 | 
			
		||||
                        gboolean             must_be_viewable,
 | 
			
		||||
                        gulong               existing_wm_state,
 | 
			
		||||
                        gboolean             has_shape,
 | 
			
		||||
                        gboolean             has_input_shape,
 | 
			
		||||
                        MetaCompEffect       effect,
 | 
			
		||||
                        XWindowAttributes   *attrs)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
  GSList *tmp;
 | 
			
		||||
  MetaWorkspace *space;
 | 
			
		||||
  gulong existing_wm_state;
 | 
			
		||||
  gulong event_mask;
 | 
			
		||||
  MetaMoveResizeFlags flags;
 | 
			
		||||
  gboolean has_shape;
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
 | 
			
		||||
  g_assert (attrs != NULL);
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
 | 
			
		||||
 | 
			
		||||
  if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Not managing no_focus_window 0x%lx\n",
 | 
			
		||||
                    xwindow);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  screen = NULL;
 | 
			
		||||
  for (tmp = display->screens; tmp != NULL; tmp = tmp->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaScreen *scr = tmp->data;
 | 
			
		||||
 | 
			
		||||
      if (scr->xroot == attrs->root)
 | 
			
		||||
        {
 | 
			
		||||
          screen = tmp->data;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_assert (screen);
 | 
			
		||||
 | 
			
		||||
  /* A black list of override redirect windows that we don't need to manage: */
 | 
			
		||||
  if (attrs->override_redirect &&
 | 
			
		||||
      (xwindow == screen->no_focus_window ||
 | 
			
		||||
       xwindow == screen->flash_window ||
 | 
			
		||||
       xwindow == screen->wm_sn_selection_window ||
 | 
			
		||||
       attrs->class == InputOnly ||
 | 
			
		||||
       /* any windows created via meta_create_offscreen_window: */
 | 
			
		||||
       (attrs->x == -100 && attrs->y == -100
 | 
			
		||||
	&& attrs->width == 1 && attrs->height == 1) ||
 | 
			
		||||
       xwindow == screen->wm_cm_selection_window ||
 | 
			
		||||
       xwindow == screen->guard_window ||
 | 
			
		||||
       (display->compositor &&
 | 
			
		||||
        xwindow == XCompositeGetOverlayWindow (display->xdisplay,
 | 
			
		||||
					       screen->xroot)
 | 
			
		||||
       )
 | 
			
		||||
      )
 | 
			
		||||
     ) {
 | 
			
		||||
    meta_verbose ("Not managing our own windows\n");
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (maybe_filter_window (display, xwindow, must_be_viewable, attrs))
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Not managing filtered window\n");
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Grab server */
 | 
			
		||||
  meta_display_grab (display);
 | 
			
		||||
  meta_error_trap_push (display); /* Push a trap over all of window
 | 
			
		||||
                                   * creation, to reduce XSync() calls
 | 
			
		||||
                                   */
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("must_be_viewable = %d attrs->map_state = %d (%s)\n",
 | 
			
		||||
                must_be_viewable,
 | 
			
		||||
                attrs->map_state,
 | 
			
		||||
@@ -897,126 +846,16 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
                "IsUnviewable" :
 | 
			
		||||
                "(unknown)");
 | 
			
		||||
 | 
			
		||||
  existing_wm_state = WithdrawnState;
 | 
			
		||||
  if (must_be_viewable && attrs->map_state != IsViewable)
 | 
			
		||||
    {
 | 
			
		||||
      /* Only manage if WM_STATE is IconicState or NormalState */
 | 
			
		||||
      gulong state;
 | 
			
		||||
 | 
			
		||||
      /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
 | 
			
		||||
      if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
 | 
			
		||||
                                                   display->atom_WM_STATE,
 | 
			
		||||
                                                   display->atom_WM_STATE,
 | 
			
		||||
                                                   &state) &&
 | 
			
		||||
            (state == IconicState || state == NormalState)))
 | 
			
		||||
        {
 | 
			
		||||
          meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
 | 
			
		||||
          meta_error_trap_pop (display);
 | 
			
		||||
          meta_display_ungrab (display);
 | 
			
		||||
          return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      existing_wm_state = state;
 | 
			
		||||
      meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
 | 
			
		||||
                    wm_state_to_string (existing_wm_state));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push_with_return (display);
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * XAddToSaveSet can only be called on windows created by a different client.
 | 
			
		||||
   * with Mutter we want to be able to create manageable windows from within
 | 
			
		||||
   * the process (such as a dummy desktop window), so we do not want this
 | 
			
		||||
   * call failing to prevent the window from being managed -- wrap it in its
 | 
			
		||||
   * own error trap (we use the _with_return() version here to ensure that
 | 
			
		||||
   * XSync() is done on the pop, otherwise the error will not get caught).
 | 
			
		||||
   */
 | 
			
		||||
  meta_error_trap_push_with_return (display);
 | 
			
		||||
  XAddToSaveSet (display->xdisplay, xwindow);
 | 
			
		||||
  meta_error_trap_pop_with_return (display);
 | 
			
		||||
 | 
			
		||||
  event_mask = PropertyChangeMask | ColormapChangeMask;
 | 
			
		||||
  if (attrs->override_redirect)
 | 
			
		||||
    event_mask |= StructureNotifyMask;
 | 
			
		||||
 | 
			
		||||
  /* If the window is from this client (a menu, say) we need to augment
 | 
			
		||||
   * the event mask, not replace it. For windows from other clients,
 | 
			
		||||
   * attrs->your_event_mask will be empty at this point.
 | 
			
		||||
   */
 | 
			
		||||
  XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
 | 
			
		||||
    XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
 | 
			
		||||
 | 
			
		||||
    meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask);
 | 
			
		||||
 | 
			
		||||
    XISetMask (mask.mask, XI_Enter);
 | 
			
		||||
    XISetMask (mask.mask, XI_Leave);
 | 
			
		||||
    XISetMask (mask.mask, XI_FocusIn);
 | 
			
		||||
    XISetMask (mask.mask, XI_FocusOut);
 | 
			
		||||
 | 
			
		||||
    XISelectEvents (display->xdisplay, xwindow, &mask, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  has_shape = FALSE;
 | 
			
		||||
#ifdef HAVE_SHAPE
 | 
			
		||||
  if (META_DISPLAY_HAS_SHAPE (display))
 | 
			
		||||
    {
 | 
			
		||||
      int x_bounding, y_bounding, x_clip, y_clip;
 | 
			
		||||
      unsigned w_bounding, h_bounding, w_clip, h_clip;
 | 
			
		||||
      int bounding_shaped, clip_shaped;
 | 
			
		||||
 | 
			
		||||
      XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
 | 
			
		||||
 | 
			
		||||
      XShapeQueryExtents (display->xdisplay, xwindow,
 | 
			
		||||
                          &bounding_shaped, &x_bounding, &y_bounding,
 | 
			
		||||
                          &w_bounding, &h_bounding,
 | 
			
		||||
                          &clip_shaped, &x_clip, &y_clip,
 | 
			
		||||
                          &w_clip, &h_clip);
 | 
			
		||||
 | 
			
		||||
      has_shape = bounding_shaped != FALSE;
 | 
			
		||||
 | 
			
		||||
      meta_topic (META_DEBUG_SHAPES,
 | 
			
		||||
                  "Window has_shape = %d extents %d,%d %u x %u\n",
 | 
			
		||||
                  has_shape, x_bounding, y_bounding,
 | 
			
		||||
                  w_bounding, h_bounding);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Get rid of any borders */
 | 
			
		||||
  if (attrs->border_width != 0)
 | 
			
		||||
    XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
 | 
			
		||||
 | 
			
		||||
  /* Get rid of weird gravities */
 | 
			
		||||
  if (attrs->win_gravity != NorthWestGravity)
 | 
			
		||||
    {
 | 
			
		||||
      XSetWindowAttributes set_attrs;
 | 
			
		||||
 | 
			
		||||
      set_attrs.win_gravity = NorthWestGravity;
 | 
			
		||||
 | 
			
		||||
      XChangeWindowAttributes (display->xdisplay,
 | 
			
		||||
                               xwindow,
 | 
			
		||||
                               CWWinGravity,
 | 
			
		||||
                               &set_attrs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (meta_error_trap_pop_with_return (display) != Success)
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
 | 
			
		||||
                    xwindow);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
      meta_display_ungrab (display);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  window = g_object_new (META_TYPE_WINDOW, NULL);
 | 
			
		||||
 | 
			
		||||
  window->constructing = TRUE;
 | 
			
		||||
 | 
			
		||||
  window->dialog_pid = -1;
 | 
			
		||||
 | 
			
		||||
  window->client_type = client_type;
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  window->surface = surface;
 | 
			
		||||
#endif
 | 
			
		||||
  window->xwindow = xwindow;
 | 
			
		||||
 | 
			
		||||
  /* this is in window->screen->display, but that's too annoying to
 | 
			
		||||
@@ -1042,6 +881,7 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  meta_stack_freeze (window->screen->stack);
 | 
			
		||||
 | 
			
		||||
  window->has_shape = has_shape;
 | 
			
		||||
  window->has_input_shape = has_input_shape;
 | 
			
		||||
 | 
			
		||||
  window->rect.x = attrs->x;
 | 
			
		||||
  window->rect.y = attrs->y;
 | 
			
		||||
@@ -1142,7 +982,11 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  window->mwm_has_move_func = TRUE;
 | 
			
		||||
  window->mwm_has_resize_func = TRUE;
 | 
			
		||||
 | 
			
		||||
  window->decorated = TRUE;
 | 
			
		||||
  if (client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    window->decorated = TRUE;
 | 
			
		||||
  else
 | 
			
		||||
    window->decorated = FALSE;
 | 
			
		||||
 | 
			
		||||
  window->has_close_func = TRUE;
 | 
			
		||||
  window->has_minimize_func = TRUE;
 | 
			
		||||
  window->has_maximize_func = TRUE;
 | 
			
		||||
@@ -1201,23 +1045,26 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
 | 
			
		||||
  window->tile_match = NULL;
 | 
			
		||||
 | 
			
		||||
  if (window->override_redirect)
 | 
			
		||||
    {
 | 
			
		||||
      window->decorated = FALSE;
 | 
			
		||||
      window->always_sticky = TRUE;
 | 
			
		||||
      window->has_close_func = FALSE;
 | 
			
		||||
      window->has_shade_func = FALSE;
 | 
			
		||||
      window->has_move_func = FALSE;
 | 
			
		||||
      window->has_resize_func = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_display_register_x_window (display, &window->xwindow, window);
 | 
			
		||||
 | 
			
		||||
  /* Assign this #MetaWindow a sequence number which can be used
 | 
			
		||||
   * for sorting.
 | 
			
		||||
   */
 | 
			
		||||
  window->stable_sequence = ++display->window_sequence_counter;
 | 
			
		||||
 | 
			
		||||
  if (client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    {
 | 
			
		||||
      if (window->override_redirect)
 | 
			
		||||
        {
 | 
			
		||||
          window->decorated = FALSE;
 | 
			
		||||
          window->always_sticky = TRUE;
 | 
			
		||||
          window->has_close_func = FALSE;
 | 
			
		||||
          window->has_shade_func = FALSE;
 | 
			
		||||
          window->has_move_func = FALSE;
 | 
			
		||||
          window->has_resize_func = FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_display_register_x_window (display, &window->xwindow, window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* assign the window to its group, or create a new group if needed
 | 
			
		||||
   */
 | 
			
		||||
  window->group = NULL;
 | 
			
		||||
@@ -1226,7 +1073,8 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
 | 
			
		||||
  meta_window_load_initial_properties (window);
 | 
			
		||||
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
  if (!window->override_redirect &&
 | 
			
		||||
      client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    {
 | 
			
		||||
      update_sm_hints (window); /* must come after transient_for */
 | 
			
		||||
 | 
			
		||||
@@ -1300,6 +1148,16 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
  if (window->decorated)
 | 
			
		||||
    meta_window_ensure_frame (window);
 | 
			
		||||
 | 
			
		||||
  if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackWindow stack_window;
 | 
			
		||||
      stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
 | 
			
		||||
      stack_window.wayland.meta_window = window;
 | 
			
		||||
      meta_stack_tracker_record_add (window->screen->stack_tracker,
 | 
			
		||||
                                     &stack_window,
 | 
			
		||||
                                     0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_window_grab_keys (window);
 | 
			
		||||
  if (window->type != META_WINDOW_DOCK && !window->override_redirect)
 | 
			
		||||
    {
 | 
			
		||||
@@ -1500,11 +1358,14 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
      !window->initially_iconic)
 | 
			
		||||
    unminimize_window_and_all_transient_parents (window);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
 | 
			
		||||
  meta_display_ungrab (display);
 | 
			
		||||
 | 
			
		||||
  window->constructing = FALSE;
 | 
			
		||||
 | 
			
		||||
  return window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
display_notify_window (MetaDisplay *display, MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  meta_display_notify_window_created (display, window);
 | 
			
		||||
 | 
			
		||||
  if (window->wm_state_demands_attention)
 | 
			
		||||
@@ -1512,6 +1373,309 @@ meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
 | 
			
		||||
  if (window->wm_hints_urgent)
 | 
			
		||||
    g_signal_emit_by_name (window->display, "window-marked-urgent", window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
MetaWindow *
 | 
			
		||||
meta_window_new_for_wayland (MetaDisplay        *display,
 | 
			
		||||
                             int                 width,
 | 
			
		||||
                             int                 height,
 | 
			
		||||
                             MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  XWindowAttributes attrs;
 | 
			
		||||
  MetaScreen *scr = display->screens->data;
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
 | 
			
		||||
  attrs.x = 0;
 | 
			
		||||
  attrs.y = 0;
 | 
			
		||||
  attrs.width = width;
 | 
			
		||||
  attrs.height = height;
 | 
			
		||||
  attrs.border_width = 0;
 | 
			
		||||
  attrs.depth = 24;
 | 
			
		||||
  attrs.visual = NULL;
 | 
			
		||||
  attrs.root = scr->xroot;
 | 
			
		||||
  attrs.class = InputOutput;
 | 
			
		||||
  attrs.bit_gravity = NorthWestGravity;
 | 
			
		||||
  attrs.win_gravity = NorthWestGravity;
 | 
			
		||||
  attrs.backing_store = 0;
 | 
			
		||||
  attrs.backing_planes = ~0;
 | 
			
		||||
  attrs.backing_pixel = 0;
 | 
			
		||||
  attrs.save_under = 0;
 | 
			
		||||
  attrs.colormap = 0;
 | 
			
		||||
  attrs.map_installed = 1;
 | 
			
		||||
  attrs.map_state = IsUnmapped;
 | 
			
		||||
  attrs.all_event_masks = ~0;
 | 
			
		||||
  attrs.your_event_mask = 0;
 | 
			
		||||
  attrs.do_not_propagate_mask = 0;
 | 
			
		||||
  attrs.override_redirect = 0;
 | 
			
		||||
  attrs.screen = scr->xscreen;
 | 
			
		||||
 | 
			
		||||
  /* XXX: Note: In the Wayland case we currently still grab the
 | 
			
		||||
   * xserver and trap X errors while creating a MetaWindow because we
 | 
			
		||||
   * will still be making various redundant X requests (passing a
 | 
			
		||||
   * window xid of None) until we thoroughly audit all the code to
 | 
			
		||||
   * make sure it knows about non X based clients...
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  /* Grab server */
 | 
			
		||||
  meta_display_grab (display);
 | 
			
		||||
  meta_error_trap_push (display); /* Push a trap over all of window
 | 
			
		||||
                                   * creation, to reduce XSync() calls
 | 
			
		||||
                                   */
 | 
			
		||||
 | 
			
		||||
  window = meta_window_new_shared (display,
 | 
			
		||||
                                   scr,
 | 
			
		||||
                                   META_WINDOW_CLIENT_TYPE_WAYLAND,
 | 
			
		||||
                                   surface,
 | 
			
		||||
                                   None,
 | 
			
		||||
                                   TRUE,
 | 
			
		||||
                                   WithdrawnState,
 | 
			
		||||
                                   FALSE, /* has shape */
 | 
			
		||||
                                   FALSE, /* has input shape */
 | 
			
		||||
                                   META_COMP_EFFECT_NONE,
 | 
			
		||||
                                   &attrs);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
 | 
			
		||||
  meta_display_ungrab (display);
 | 
			
		||||
 | 
			
		||||
  /* XXX: Maybe this could be called in meta_window_new_shared() but
 | 
			
		||||
   * before splitting the X11 specific code out it came after the
 | 
			
		||||
   * meta_display_ungrab() and we wanted to minimize the risk of
 | 
			
		||||
   * breaking something.
 | 
			
		||||
   */
 | 
			
		||||
  display_notify_window (window->display, window);
 | 
			
		||||
 | 
			
		||||
  return window;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MetaWindow*
 | 
			
		||||
meta_window_new_with_attrs (MetaDisplay       *display,
 | 
			
		||||
                            Window             xwindow,
 | 
			
		||||
                            gboolean           must_be_viewable,
 | 
			
		||||
                            MetaCompEffect     effect,
 | 
			
		||||
                            XWindowAttributes *attrs)
 | 
			
		||||
{
 | 
			
		||||
  MetaScreen *screen = NULL;
 | 
			
		||||
  GSList *tmp;
 | 
			
		||||
  gulong existing_wm_state;
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
  gulong event_mask;
 | 
			
		||||
  gboolean has_shape = FALSE;
 | 
			
		||||
  gboolean has_input_shape = FALSE;
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
 | 
			
		||||
 | 
			
		||||
  if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Not managing no_focus_window 0x%lx\n",
 | 
			
		||||
                    xwindow);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (tmp = display->screens; tmp != NULL; tmp = tmp->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaScreen *scr = tmp->data;
 | 
			
		||||
 | 
			
		||||
      if (scr->xroot == attrs->root)
 | 
			
		||||
        {
 | 
			
		||||
          screen = tmp->data;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_assert (screen);
 | 
			
		||||
 | 
			
		||||
  /* A black list of override redirect windows that we don't need to manage: */
 | 
			
		||||
  if (attrs->override_redirect &&
 | 
			
		||||
      (xwindow == screen->no_focus_window ||
 | 
			
		||||
       xwindow == screen->flash_window ||
 | 
			
		||||
       xwindow == screen->wm_sn_selection_window ||
 | 
			
		||||
       attrs->class == InputOnly ||
 | 
			
		||||
       /* any windows created via meta_create_offscreen_window: */
 | 
			
		||||
       (attrs->x == -100 && attrs->y == -100
 | 
			
		||||
	&& attrs->width == 1 && attrs->height == 1) ||
 | 
			
		||||
       xwindow == screen->wm_cm_selection_window ||
 | 
			
		||||
       xwindow == screen->guard_window ||
 | 
			
		||||
       (display->compositor &&
 | 
			
		||||
        xwindow == XCompositeGetOverlayWindow (display->xdisplay,
 | 
			
		||||
					       screen->xroot)
 | 
			
		||||
       )
 | 
			
		||||
      )
 | 
			
		||||
     ) {
 | 
			
		||||
    meta_verbose ("Not managing our own windows\n");
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (maybe_filter_xwindow (display, xwindow, must_be_viewable, attrs))
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Not managing filtered window\n");
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Grab server */
 | 
			
		||||
  meta_display_grab (display);
 | 
			
		||||
  meta_error_trap_push (display); /* Push a trap over all of window
 | 
			
		||||
                                   * creation, to reduce XSync() calls
 | 
			
		||||
                                   */
 | 
			
		||||
 | 
			
		||||
  existing_wm_state = WithdrawnState;
 | 
			
		||||
  if (must_be_viewable && attrs->map_state != IsViewable)
 | 
			
		||||
    {
 | 
			
		||||
      /* Only manage if WM_STATE is IconicState or NormalState */
 | 
			
		||||
      gulong state;
 | 
			
		||||
 | 
			
		||||
      /* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
 | 
			
		||||
      if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
 | 
			
		||||
                                                   display->atom_WM_STATE,
 | 
			
		||||
                                                   display->atom_WM_STATE,
 | 
			
		||||
                                                   &state) &&
 | 
			
		||||
            (state == IconicState || state == NormalState)))
 | 
			
		||||
        {
 | 
			
		||||
          meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
 | 
			
		||||
          meta_error_trap_pop (display);
 | 
			
		||||
          meta_display_ungrab (display);
 | 
			
		||||
          return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      existing_wm_state = state;
 | 
			
		||||
      meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
 | 
			
		||||
                    wm_state_to_string (existing_wm_state));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push_with_return (display);
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * XAddToSaveSet can only be called on windows created by a different
 | 
			
		||||
   * client.  with Mutter we want to be able to create manageable windows
 | 
			
		||||
   * from within the process (such as a dummy desktop window), so we do not
 | 
			
		||||
   * want this call failing to prevent the window from being managed -- wrap
 | 
			
		||||
   * it in its own error trap (we use the _with_return() version here to
 | 
			
		||||
   * ensure that XSync() is done on the pop, otherwise the error will not
 | 
			
		||||
   * get caught).
 | 
			
		||||
   */
 | 
			
		||||
  meta_error_trap_push_with_return (display);
 | 
			
		||||
  XAddToSaveSet (display->xdisplay, xwindow);
 | 
			
		||||
  meta_error_trap_pop_with_return (display);
 | 
			
		||||
 | 
			
		||||
  event_mask = PropertyChangeMask | ColormapChangeMask;
 | 
			
		||||
  if (attrs->override_redirect)
 | 
			
		||||
    event_mask |= StructureNotifyMask;
 | 
			
		||||
 | 
			
		||||
  /* If the window is from this client (a menu, say) we need to augment
 | 
			
		||||
   * the event mask, not replace it. For windows from other clients,
 | 
			
		||||
   * attrs->your_event_mask will be empty at this point.
 | 
			
		||||
   */
 | 
			
		||||
  XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
      unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
 | 
			
		||||
      XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
 | 
			
		||||
 | 
			
		||||
      meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask);
 | 
			
		||||
 | 
			
		||||
      XISetMask (mask.mask, XI_Enter);
 | 
			
		||||
      XISetMask (mask.mask, XI_Leave);
 | 
			
		||||
      XISetMask (mask.mask, XI_FocusIn);
 | 
			
		||||
      XISetMask (mask.mask, XI_FocusOut);
 | 
			
		||||
 | 
			
		||||
      XISelectEvents (display->xdisplay, xwindow, &mask, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SHAPE
 | 
			
		||||
  if (META_DISPLAY_HAS_SHAPE (display))
 | 
			
		||||
    {
 | 
			
		||||
      int x_bounding, y_bounding, x_clip, y_clip;
 | 
			
		||||
      unsigned w_bounding, h_bounding, w_clip, h_clip;
 | 
			
		||||
      int bounding_shaped, clip_shaped;
 | 
			
		||||
      XRectangle *input_rectangles;
 | 
			
		||||
      int n_rects, ordering;
 | 
			
		||||
 | 
			
		||||
      XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
 | 
			
		||||
 | 
			
		||||
      XShapeQueryExtents (display->xdisplay, xwindow,
 | 
			
		||||
                          &bounding_shaped, &x_bounding, &y_bounding,
 | 
			
		||||
                          &w_bounding, &h_bounding,
 | 
			
		||||
                          &clip_shaped, &x_clip, &y_clip,
 | 
			
		||||
                          &w_clip, &h_clip);
 | 
			
		||||
 | 
			
		||||
      has_shape = bounding_shaped != FALSE;
 | 
			
		||||
 | 
			
		||||
      /* XXX: The x shape extension doesn't provide a way to only test if an
 | 
			
		||||
       * input shape has been specified, so we have to query and throw away the
 | 
			
		||||
       * rectangles. */
 | 
			
		||||
      meta_error_trap_push (display);
 | 
			
		||||
      input_rectangles = XShapeGetRectangles (display->xdisplay, xwindow,
 | 
			
		||||
                                              ShapeInput, &n_rects, &ordering);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
      if (input_rectangles)
 | 
			
		||||
        {
 | 
			
		||||
          if (n_rects > 1 ||
 | 
			
		||||
              (n_rects == 1 &&
 | 
			
		||||
               (input_rectangles[0].x != x_bounding ||
 | 
			
		||||
                input_rectangles[1].y != y_bounding ||
 | 
			
		||||
                input_rectangles[2].width != w_bounding ||
 | 
			
		||||
                input_rectangles[3].height != h_bounding)))
 | 
			
		||||
            {
 | 
			
		||||
              has_input_shape = TRUE;
 | 
			
		||||
            }
 | 
			
		||||
          XFree (input_rectangles);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_topic (META_DEBUG_SHAPES,
 | 
			
		||||
                  "Window has_shape = %d extents %d,%d %u x %u\n",
 | 
			
		||||
                  has_shape, x_bounding, y_bounding,
 | 
			
		||||
                  w_bounding, h_bounding);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Get rid of any borders */
 | 
			
		||||
  if (attrs->border_width != 0)
 | 
			
		||||
    XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
 | 
			
		||||
 | 
			
		||||
  /* Get rid of weird gravities */
 | 
			
		||||
  if (attrs->win_gravity != NorthWestGravity)
 | 
			
		||||
    {
 | 
			
		||||
      XSetWindowAttributes set_attrs;
 | 
			
		||||
 | 
			
		||||
      set_attrs.win_gravity = NorthWestGravity;
 | 
			
		||||
 | 
			
		||||
      XChangeWindowAttributes (display->xdisplay,
 | 
			
		||||
                               xwindow,
 | 
			
		||||
                               CWWinGravity,
 | 
			
		||||
                               &set_attrs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (meta_error_trap_pop_with_return (display) != Success)
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
 | 
			
		||||
                    xwindow);
 | 
			
		||||
      meta_error_trap_pop (display);
 | 
			
		||||
      meta_display_ungrab (display);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  window = meta_window_new_shared (display,
 | 
			
		||||
                                   screen,
 | 
			
		||||
                                   META_WINDOW_CLIENT_TYPE_X11,
 | 
			
		||||
                                   NULL,
 | 
			
		||||
                                   xwindow,
 | 
			
		||||
                                   must_be_viewable,
 | 
			
		||||
                                   existing_wm_state,
 | 
			
		||||
                                   has_shape,
 | 
			
		||||
                                   has_input_shape,
 | 
			
		||||
                                   effect,
 | 
			
		||||
                                   attrs);
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
 | 
			
		||||
  meta_display_ungrab (display);
 | 
			
		||||
 | 
			
		||||
  /* XXX: Maybe this could be called in meta_window_new_shared() but
 | 
			
		||||
   * before splitting the X11 specific code out it came after the
 | 
			
		||||
   * meta_display_ungrab() and we wanted to minimize the risk of
 | 
			
		||||
   * breaking something.
 | 
			
		||||
   */
 | 
			
		||||
  display_notify_window (display, window);
 | 
			
		||||
 | 
			
		||||
  return window;
 | 
			
		||||
}
 | 
			
		||||
@@ -1682,6 +1846,16 @@ meta_window_unmanage (MetaWindow  *window,
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
 | 
			
		||||
 | 
			
		||||
  if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStackWindow stack_window;
 | 
			
		||||
      stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
 | 
			
		||||
      stack_window.wayland.meta_window = window;
 | 
			
		||||
      meta_stack_tracker_record_remove (window->screen->stack_tracker,
 | 
			
		||||
                                        &stack_window,
 | 
			
		||||
                                        0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (window->display->compositor)
 | 
			
		||||
    {
 | 
			
		||||
      if (window->visible_to_compositor)
 | 
			
		||||
@@ -1888,48 +2062,55 @@ meta_window_unmanage (MetaWindow  *window,
 | 
			
		||||
  meta_display_ungrab_window_buttons (window->display, window->xwindow);
 | 
			
		||||
  meta_display_ungrab_focus_window_button (window->display, window);
 | 
			
		||||
 | 
			
		||||
  meta_display_unregister_x_window (window->display, window->xwindow);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_push (window->display);
 | 
			
		||||
 | 
			
		||||
  /* Put back anything we messed up */
 | 
			
		||||
  if (window->border_width != 0)
 | 
			
		||||
    XSetWindowBorderWidth (window->display->xdisplay,
 | 
			
		||||
                           window->xwindow,
 | 
			
		||||
                           window->border_width);
 | 
			
		||||
 | 
			
		||||
  /* No save set */
 | 
			
		||||
  XRemoveFromSaveSet (window->display->xdisplay,
 | 
			
		||||
                      window->xwindow);
 | 
			
		||||
 | 
			
		||||
  /* Even though the window is now unmanaged, we can't unselect events. This
 | 
			
		||||
   * window might be a window from this process, like a GdkMenu, in
 | 
			
		||||
   * which case it will have pointer events and so forth selected
 | 
			
		||||
   * for it by GDK. There's no way to disentangle those events from the events
 | 
			
		||||
   * we've selected. Even for a window from a different X client,
 | 
			
		||||
   * GDK could also have selected events for it for IPC purposes, so we
 | 
			
		||||
   * can't unselect in that case either.
 | 
			
		||||
   *
 | 
			
		||||
   * Similarly, we can't unselected for events on window->user_time_window.
 | 
			
		||||
   * It might be our own GDK focus window, or it might be a window that a
 | 
			
		||||
   * different client is using for multiple different things:
 | 
			
		||||
   * _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  if (window->user_time_window != None)
 | 
			
		||||
  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
 | 
			
		||||
    {
 | 
			
		||||
      meta_display_unregister_x_window (window->display,
 | 
			
		||||
                                        window->user_time_window);
 | 
			
		||||
      window->user_time_window = None;
 | 
			
		||||
    }
 | 
			
		||||
      meta_display_unregister_x_window (window->display, window->xwindow);
 | 
			
		||||
 | 
			
		||||
      meta_error_trap_push (window->display);
 | 
			
		||||
 | 
			
		||||
      /* Put back anything we messed up */
 | 
			
		||||
      if (window->border_width != 0)
 | 
			
		||||
        XSetWindowBorderWidth (window->display->xdisplay,
 | 
			
		||||
                               window->xwindow,
 | 
			
		||||
                               window->border_width);
 | 
			
		||||
 | 
			
		||||
      /* No save set */
 | 
			
		||||
      XRemoveFromSaveSet (window->display->xdisplay,
 | 
			
		||||
                          window->xwindow);
 | 
			
		||||
 | 
			
		||||
      /* Even though the window is now unmanaged, we can't unselect events. This
 | 
			
		||||
       * window might be a window from this process, like a GdkMenu, in
 | 
			
		||||
       * which case it will have pointer events and so forth selected
 | 
			
		||||
       * for it by GDK. There's no way to disentangle those events from the events
 | 
			
		||||
       * we've selected. Even for a window from a different X client,
 | 
			
		||||
       * GDK could also have selected events for it for IPC purposes, so we
 | 
			
		||||
       * can't unselect in that case either.
 | 
			
		||||
       *
 | 
			
		||||
       * Similarly, we can't unselected for events on window->user_time_window.
 | 
			
		||||
       * It might be our own GDK focus window, or it might be a window that a
 | 
			
		||||
       * different client is using for multiple different things:
 | 
			
		||||
       * _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
 | 
			
		||||
       */
 | 
			
		||||
 | 
			
		||||
      if (window->user_time_window != None)
 | 
			
		||||
        {
 | 
			
		||||
          meta_display_unregister_x_window (window->display,
 | 
			
		||||
                                            window->user_time_window);
 | 
			
		||||
          window->user_time_window = None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SHAPE
 | 
			
		||||
  if (META_DISPLAY_HAS_SHAPE (window->display))
 | 
			
		||||
    XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
 | 
			
		||||
      if (META_DISPLAY_HAS_SHAPE (window->display))
 | 
			
		||||
        XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_error_trap_pop (window->display);
 | 
			
		||||
      meta_error_trap_pop (window->display);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (window->surface)
 | 
			
		||||
    meta_wayland_surface_free (window->surface);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_prefs_remove_listener (prefs_changed_callback, window);
 | 
			
		||||
 | 
			
		||||
@@ -2108,10 +2289,14 @@ set_net_wm_state (MetaWindow *window)
 | 
			
		||||
 | 
			
		||||
  if (window->fullscreen)
 | 
			
		||||
    {
 | 
			
		||||
      data[0] = window->fullscreen_monitors[0];
 | 
			
		||||
      data[1] = window->fullscreen_monitors[1];
 | 
			
		||||
      data[2] = window->fullscreen_monitors[2];
 | 
			
		||||
      data[3] = window->fullscreen_monitors[3];
 | 
			
		||||
      data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen,
 | 
			
		||||
                                                             window->fullscreen_monitors[0]);
 | 
			
		||||
      data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen,
 | 
			
		||||
                                                             window->fullscreen_monitors[1]);
 | 
			
		||||
      data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen,
 | 
			
		||||
                                                             window->fullscreen_monitors[2]);
 | 
			
		||||
      data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen,
 | 
			
		||||
                                                             window->fullscreen_monitors[3]);
 | 
			
		||||
 | 
			
		||||
      meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
 | 
			
		||||
      meta_error_trap_push (window->display);
 | 
			
		||||
@@ -4785,7 +4970,8 @@ meta_window_update_for_monitors_changed (MetaWindow *window)
 | 
			
		||||
    {
 | 
			
		||||
      MetaMonitorInfo *info = &window->screen->monitor_infos[i];
 | 
			
		||||
 | 
			
		||||
      if (info->output == old->output)
 | 
			
		||||
      if (info->output_id != 0 &&
 | 
			
		||||
          info->output_id == old->output_id)
 | 
			
		||||
        {
 | 
			
		||||
          new = info;
 | 
			
		||||
          break;
 | 
			
		||||
@@ -7130,10 +7316,14 @@ meta_window_client_message (MetaWindow *window,
 | 
			
		||||
      meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n",
 | 
			
		||||
                    window->desc);
 | 
			
		||||
 | 
			
		||||
      top = event->xclient.data.l[0];
 | 
			
		||||
      bottom = event->xclient.data.l[1];
 | 
			
		||||
      left = event->xclient.data.l[2];
 | 
			
		||||
      right = event->xclient.data.l[3];
 | 
			
		||||
      top = meta_screen_xinerama_index_to_monitor_index (window->screen,
 | 
			
		||||
                                                         event->xclient.data.l[0]);
 | 
			
		||||
      bottom = meta_screen_xinerama_index_to_monitor_index (window->screen,
 | 
			
		||||
                                                            event->xclient.data.l[1]);
 | 
			
		||||
      left = meta_screen_xinerama_index_to_monitor_index (window->screen,
 | 
			
		||||
                                                          event->xclient.data.l[2]);
 | 
			
		||||
      right = meta_screen_xinerama_index_to_monitor_index (window->screen,
 | 
			
		||||
                                                           event->xclient.data.l[3]);
 | 
			
		||||
      /* source_indication = event->xclient.data.l[4]; */
 | 
			
		||||
 | 
			
		||||
      meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
 | 
			
		||||
@@ -7209,6 +7399,9 @@ void
 | 
			
		||||
meta_window_set_focused_internal (MetaWindow *window,
 | 
			
		||||
                                  gboolean    focused)
 | 
			
		||||
{
 | 
			
		||||
  if (window->unmanaging)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (focused)
 | 
			
		||||
    {
 | 
			
		||||
      window->has_focus = TRUE;
 | 
			
		||||
@@ -7682,7 +7875,7 @@ meta_window_update_opaque_region (MetaWindow *window)
 | 
			
		||||
  meta_XFree (region);
 | 
			
		||||
 | 
			
		||||
  if (window->display->compositor)
 | 
			
		||||
    meta_compositor_window_shape_changed (window->display->compositor, window);
 | 
			
		||||
    meta_compositor_window_x11_shape_changed (window->display->compositor, window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,7 @@ item(_MUTTER_TIMESTAMP_PING)
 | 
			
		||||
item(_MUTTER_FOCUS_SET)
 | 
			
		||||
item(_MUTTER_SENTINEL)
 | 
			
		||||
item(_MUTTER_VERSION)
 | 
			
		||||
item(_MUTTER_PRESENTATION_OUTPUT)
 | 
			
		||||
item(WM_CLIENT_MACHINE)
 | 
			
		||||
item(MANAGER)
 | 
			
		||||
item(TARGETS)
 | 
			
		||||
@@ -79,6 +80,7 @@ item(MULTIPLE)
 | 
			
		||||
item(TIMESTAMP)
 | 
			
		||||
item(VERSION)
 | 
			
		||||
item(ATOM_PAIR)
 | 
			
		||||
item(BACKLIGHT)
 | 
			
		||||
 | 
			
		||||
/* Oddities: These are used, and we need atoms for them,
 | 
			
		||||
 * but when we need all _NET_WM hints (i.e. when we're making
 | 
			
		||||
 
 | 
			
		||||
@@ -64,8 +64,8 @@ void meta_compositor_manage_screen   (MetaCompositor *compositor,
 | 
			
		||||
void meta_compositor_unmanage_screen (MetaCompositor *compositor,
 | 
			
		||||
                                      MetaScreen     *screen);
 | 
			
		||||
 | 
			
		||||
void meta_compositor_window_shape_changed (MetaCompositor *compositor,
 | 
			
		||||
                                           MetaWindow     *window);
 | 
			
		||||
void meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
 | 
			
		||||
                                               MetaWindow     *window);
 | 
			
		||||
 | 
			
		||||
gboolean meta_compositor_process_event (MetaCompositor *compositor,
 | 
			
		||||
                                        XEvent         *event,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										49
									
								
								src/meta/meta-cursor-tracker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/meta/meta-cursor-tracker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Giovanni Campagna <gcampagn@redhat.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_CURSOR_TRACKER_H
 | 
			
		||||
#define META_CURSOR_TRACKER_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <meta/types.h>
 | 
			
		||||
#include <meta/workspace.h>
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_CURSOR_TRACKER            (meta_cursor_tracker_get_type ())
 | 
			
		||||
#define META_CURSOR_TRACKER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTracker))
 | 
			
		||||
#define META_CURSOR_TRACKER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass))
 | 
			
		||||
#define META_IS_CURSOR_TRACKER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER))
 | 
			
		||||
#define META_IS_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_CURSOR_TRACKER))
 | 
			
		||||
#define META_CURSOR_TRACKER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaCursorTrackerClass   MetaCursorTrackerClass;
 | 
			
		||||
 | 
			
		||||
GType meta_cursor_tracker_get_type (void);
 | 
			
		||||
 | 
			
		||||
MetaCursorTracker *meta_cursor_tracker_get_for_screen (MetaScreen *screen);
 | 
			
		||||
 | 
			
		||||
void           meta_cursor_tracker_get_hot    (MetaCursorTracker *tracker,
 | 
			
		||||
                                               int               *x,
 | 
			
		||||
                                               int               *y);
 | 
			
		||||
CoglTexture   *meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										62
									
								
								src/meta/meta-idle-monitor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/meta/meta-idle-monitor.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_IDLE_MONITOR_H
 | 
			
		||||
#define META_IDLE_MONITOR_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <meta/types.h>
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_IDLE_MONITOR            (meta_idle_monitor_get_type ())
 | 
			
		||||
#define META_IDLE_MONITOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR, MetaIdleMonitor))
 | 
			
		||||
#define META_IDLE_MONITOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_IDLE_MONITOR, MetaIdleMonitorClass))
 | 
			
		||||
#define META_IS_IDLE_MONITOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR))
 | 
			
		||||
#define META_IS_IDLE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_IDLE_MONITOR))
 | 
			
		||||
#define META_IDLE_MONITOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_IDLE_MONITOR, MetaIdleMonitorClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaIdleMonitor        MetaIdleMonitor;
 | 
			
		||||
typedef struct _MetaIdleMonitorClass   MetaIdleMonitorClass;
 | 
			
		||||
 | 
			
		||||
GType meta_idle_monitor_get_type (void);
 | 
			
		||||
 | 
			
		||||
typedef void (*MetaIdleMonitorWatchFunc) (MetaIdleMonitor *monitor,
 | 
			
		||||
                                          guint            watch_id,
 | 
			
		||||
                                          gpointer         user_data);
 | 
			
		||||
 | 
			
		||||
MetaIdleMonitor *meta_idle_monitor_get_core (void);
 | 
			
		||||
MetaIdleMonitor *meta_idle_monitor_get_for_device (int device_id);
 | 
			
		||||
 | 
			
		||||
guint         meta_idle_monitor_add_idle_watch        (MetaIdleMonitor          *monitor,
 | 
			
		||||
						       guint64                   interval_msec,
 | 
			
		||||
						       MetaIdleMonitorWatchFunc  callback,
 | 
			
		||||
						       gpointer                  user_data,
 | 
			
		||||
						       GDestroyNotify            notify);
 | 
			
		||||
 | 
			
		||||
guint         meta_idle_monitor_add_user_active_watch (MetaIdleMonitor          *monitor,
 | 
			
		||||
						       MetaIdleMonitorWatchFunc  callback,
 | 
			
		||||
						       gpointer                  user_data,
 | 
			
		||||
						       GDestroyNotify            notify);
 | 
			
		||||
 | 
			
		||||
void          meta_idle_monitor_remove_watch          (MetaIdleMonitor          *monitor,
 | 
			
		||||
						       guint                     id);
 | 
			
		||||
guint64       meta_idle_monitor_get_idletime          (MetaIdleMonitor          *monitor);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -205,6 +205,21 @@ struct _MetaPluginClass
 | 
			
		||||
  gboolean (*keybinding_filter) (MetaPlugin     *plugin,
 | 
			
		||||
                                 MetaKeyBinding *binding);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * MetaPluginClass::confirm_display_config:
 | 
			
		||||
   * @plugin: a #MetaPlugin
 | 
			
		||||
   *
 | 
			
		||||
   * Virtual function called when the display configuration changes.
 | 
			
		||||
   * The common way to implement this function is to show some form
 | 
			
		||||
   * of modal dialog that should ask the user if everything was ok.
 | 
			
		||||
   *
 | 
			
		||||
   * When confirmed by the user, the plugin must call meta_plugin_complete_display_change()
 | 
			
		||||
   * to make the configuration permanent. If that function is not
 | 
			
		||||
   * called within the timeout, the previous configuration will be
 | 
			
		||||
   * reapplied.
 | 
			
		||||
   */
 | 
			
		||||
  void (*confirm_display_change) (MetaPlugin *plugin);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * MetaPluginClass::plugin_info:
 | 
			
		||||
   * @plugin: a #MetaPlugin
 | 
			
		||||
@@ -214,6 +229,7 @@ struct _MetaPluginClass
 | 
			
		||||
   * Returns: a #MetaPluginInfo.
 | 
			
		||||
   */
 | 
			
		||||
  const MetaPluginInfo * (*plugin_info) (MetaPlugin *plugin);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -360,6 +376,10 @@ void
 | 
			
		||||
meta_plugin_destroy_completed (MetaPlugin      *plugin,
 | 
			
		||||
                               MetaWindowActor *actor);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_plugin_complete_display_change (MetaPlugin *plugin,
 | 
			
		||||
                                     gboolean    ok);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MetaModalOptions:
 | 
			
		||||
 * @META_MODAL_POINTER_ALREADY_GRABBED: if set the pointer is already
 | 
			
		||||
@@ -376,8 +396,6 @@ typedef enum {
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_plugin_begin_modal (MetaPlugin      *plugin,
 | 
			
		||||
                         Window           grab_window,
 | 
			
		||||
                         Cursor           cursor,
 | 
			
		||||
                         MetaModalOptions options,
 | 
			
		||||
                         guint32          timestamp);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,11 @@
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_SHAPED_TEXTURE            (meta_shaped_texture_get_type())
 | 
			
		||||
@@ -64,7 +69,13 @@ struct _MetaShapedTexture
 | 
			
		||||
 | 
			
		||||
GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
ClutterActor *meta_shaped_texture_new (void);
 | 
			
		||||
ClutterActor *meta_shaped_texture_new_with_xwindow (Window xwindow);
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
ClutterActor *meta_shaped_texture_new_with_wayland_surface  (MetaWaylandSurface *surface);
 | 
			
		||||
void meta_shaped_texture_set_wayland_surface                (MetaShapedTexture  *stex,
 | 
			
		||||
                                                             MetaWaylandSurface *surface);
 | 
			
		||||
MetaWaylandSurface *meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
 | 
			
		||||
					     gboolean           create_mipmaps);
 | 
			
		||||
@@ -77,11 +88,17 @@ void meta_shaped_texture_update_area (MetaShapedTexture *stex,
 | 
			
		||||
 | 
			
		||||
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
 | 
			
		||||
                                     Pixmap             pixmap);
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
void meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture  *stex,
 | 
			
		||||
                                                MetaWaylandBuffer  *buffer);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
 | 
			
		||||
 | 
			
		||||
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
 | 
			
		||||
                                           CoglTexture       *mask_texture);
 | 
			
		||||
void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
 | 
			
		||||
                                                 cairo_region_t    *shape_region);
 | 
			
		||||
 | 
			
		||||
/* Assumes ownership of clip_region */
 | 
			
		||||
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
 | 
			
		||||
 
 | 
			
		||||
@@ -38,5 +38,6 @@ typedef struct _MetaWorkspace   MetaWorkspace;
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _MetaGroup       MetaGroup;
 | 
			
		||||
typedef struct _MetaKeyBinding  MetaKeyBinding;
 | 
			
		||||
typedef struct _MetaCursorTracker MetaCursorTracker;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,8 @@ void     meta_set_debugging (gboolean setting);
 | 
			
		||||
gboolean meta_is_syncing (void);
 | 
			
		||||
void     meta_set_syncing (gboolean setting);
 | 
			
		||||
void     meta_set_replace_current_wm (gboolean setting);
 | 
			
		||||
gboolean meta_is_wayland_compositor (void);
 | 
			
		||||
void     meta_set_is_wayland_compositor (gboolean setting);
 | 
			
		||||
 | 
			
		||||
void meta_debug_spew_real (const char *format,
 | 
			
		||||
                           ...) G_GNUC_PRINTF (1, 2);
 | 
			
		||||
@@ -100,7 +102,8 @@ typedef enum
 | 
			
		||||
  META_DEBUG_RESIZING        = 1 << 18,
 | 
			
		||||
  META_DEBUG_SHAPES          = 1 << 19,
 | 
			
		||||
  META_DEBUG_COMPOSITOR      = 1 << 20,
 | 
			
		||||
  META_DEBUG_EDGE_RESISTANCE = 1 << 21
 | 
			
		||||
  META_DEBUG_EDGE_RESISTANCE = 1 << 21,
 | 
			
		||||
  META_DEBUG_DBUS            = 1 << 22
 | 
			
		||||
} MetaDebugTopic;
 | 
			
		||||
 | 
			
		||||
void meta_topic_real      (MetaDebugTopic topic,
 | 
			
		||||
 
 | 
			
		||||
@@ -81,6 +81,16 @@ typedef enum
 | 
			
		||||
  META_MAXIMIZE_VERTICAL   = 1 << 1
 | 
			
		||||
} MetaMaximizeFlags;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MetaWindowClientType:
 | 
			
		||||
 * @META_WINDOW_CLIENT_TYPE_WAYLAND: A Wayland based window
 | 
			
		||||
 * @META_WINDOW_CLIENT_TYPE_X11: An X11 based window
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
  META_WINDOW_CLIENT_TYPE_WAYLAND,
 | 
			
		||||
  META_WINDOW_CLIENT_TYPE_X11
 | 
			
		||||
} MetaWindowClientType;
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_WINDOW            (meta_window_get_type ())
 | 
			
		||||
#define META_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW, MetaWindow))
 | 
			
		||||
#define META_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_WINDOW, MetaWindowClass))
 | 
			
		||||
 
 | 
			
		||||
@@ -116,5 +116,34 @@
 | 
			
		||||
      <_summary>Cancel tab popup</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
 | 
			
		||||
    <key name="switch-to-session-1" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F1']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 1</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-2" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F2']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 2</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-3" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F3']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 3</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-4" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F4']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 4</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-5" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F5']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 5</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-6" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F6']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 6</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-7" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F7']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 7</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
 | 
			
		||||
  </schema>
 | 
			
		||||
</schemalist>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										436
									
								
								src/wayland/meta-tty.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								src/wayland/meta-tty.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,436 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2010 Intel Corporation
 | 
			
		||||
 *             2013 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <linux/kd.h>
 | 
			
		||||
#include <linux/vt.h>
 | 
			
		||||
#include <linux/major.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-tty.h"
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <glib-unix.h>
 | 
			
		||||
 | 
			
		||||
/* Introduced in 2.6.38 */
 | 
			
		||||
#ifndef K_OFF
 | 
			
		||||
#define K_OFF 0x04
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct _MetaTTYClass
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaTTY
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  int fd;
 | 
			
		||||
  struct termios terminal_attributes;
 | 
			
		||||
 | 
			
		||||
  GMainContext *nested_context;
 | 
			
		||||
  GMainLoop *nested_loop;
 | 
			
		||||
 | 
			
		||||
  int input_source;
 | 
			
		||||
  GSource *vt_enter_source, *vt_leave_source;
 | 
			
		||||
  GSource *nested_term;
 | 
			
		||||
  int vt, starting_vt;
 | 
			
		||||
  int kb_mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  SIGNAL_ENTER,
 | 
			
		||||
  SIGNAL_LEAVE,
 | 
			
		||||
  SIGNAL_LAST
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int signals[SIGNAL_LAST];
 | 
			
		||||
 | 
			
		||||
static void meta_tty_initable_iface_init (GInitableIface *);
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_CODE (MetaTTY, meta_tty, G_TYPE_OBJECT,
 | 
			
		||||
			 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
 | 
			
		||||
						meta_tty_initable_iface_init));
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
quit_nested_loop (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaTTY *tty = user_data;
 | 
			
		||||
 | 
			
		||||
  g_main_loop_quit (tty->nested_loop);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
vt_release_handler (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaTTY *tty = user_data;
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (tty, signals[SIGNAL_LEAVE], 0);
 | 
			
		||||
 | 
			
		||||
  ioctl (tty->fd, VT_RELDISP, 1);
 | 
			
		||||
 | 
			
		||||
  /* We can't do anything at this point, because we don't
 | 
			
		||||
     have input devices and we don't have the DRM master,
 | 
			
		||||
     so let's run a nested busy loop until the VT is reentered */
 | 
			
		||||
  g_main_loop_run (tty->nested_loop);
 | 
			
		||||
 | 
			
		||||
  ioctl (tty->fd, VT_RELDISP, VT_ACKACQ);
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (tty, signals[SIGNAL_ENTER], 0);
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
on_tty_input (int          fd, 
 | 
			
		||||
	      GIOCondition mask,
 | 
			
		||||
	      gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaTTY *tty = user_data;
 | 
			
		||||
 | 
			
		||||
  /* Ignore input to tty.  We get keyboard events from evdev */
 | 
			
		||||
  tcflush(tty->fd, TCIFLUSH);
 | 
			
		||||
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
try_open_vt (MetaTTY  *tty,
 | 
			
		||||
	     GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  int tty0, fd;
 | 
			
		||||
  char filename[16];
 | 
			
		||||
 | 
			
		||||
  tty0 = open ("/dev/tty0", O_WRONLY | O_CLOEXEC);
 | 
			
		||||
  if (tty0 < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		   g_io_error_from_errno (errno),
 | 
			
		||||
		   "Could not open tty0: %s", strerror (errno));
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (ioctl (tty0, VT_OPENQRY, &tty->vt) < 0 || tty->vt == -1) {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		   g_io_error_from_errno (errno),
 | 
			
		||||
		   "Could not open tty0: %s", strerror (errno));
 | 
			
		||||
      close (tty0);
 | 
			
		||||
      return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  close (tty0);
 | 
			
		||||
  snprintf (filename, sizeof filename, "/dev/tty%d", tty->vt);
 | 
			
		||||
  g_debug("compositor: using new vt %s\n", filename);
 | 
			
		||||
  fd = open (filename, O_RDWR | O_NOCTTY | O_CLOEXEC);
 | 
			
		||||
  return fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_tty_activate_vt (MetaTTY  *tty,
 | 
			
		||||
		      int       vt,
 | 
			
		||||
		      GError  **error)
 | 
			
		||||
{
 | 
			
		||||
  if (ioctl(tty->fd, VT_ACTIVATE, vt) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
 | 
			
		||||
		   strerror (errno));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
env_get_fd (const char *env)
 | 
			
		||||
{
 | 
			
		||||
  const char *value;
 | 
			
		||||
 | 
			
		||||
  value = g_getenv (env);
 | 
			
		||||
 | 
			
		||||
  if (value == NULL)
 | 
			
		||||
    return -1;
 | 
			
		||||
  else
 | 
			
		||||
    return g_ascii_strtoll (value, NULL, 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_tty_initable_init(GInitable     *initable,
 | 
			
		||||
		       GCancellable  *cancellable,
 | 
			
		||||
		       GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaTTY *tty = META_TTY (initable);
 | 
			
		||||
  struct termios raw_attributes;
 | 
			
		||||
  struct vt_mode mode = { 0 };
 | 
			
		||||
  int ret;
 | 
			
		||||
	
 | 
			
		||||
  struct stat buf;
 | 
			
		||||
  struct vt_stat vts;
 | 
			
		||||
 | 
			
		||||
  tty->fd = env_get_fd ("WESTON_TTY_FD");
 | 
			
		||||
  if (tty->fd < 0)
 | 
			
		||||
    tty->fd = STDIN_FILENO;
 | 
			
		||||
 | 
			
		||||
  if (fstat(tty->fd, &buf) == 0 &&
 | 
			
		||||
      major(buf.st_rdev) == TTY_MAJOR &&
 | 
			
		||||
      minor(buf.st_rdev) > 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (tty->fd == STDIN_FILENO)
 | 
			
		||||
	tty->fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0);
 | 
			
		||||
      tty->vt = minor(buf.st_rdev);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Fall back to try opening a new VT.  This typically
 | 
			
		||||
       * requires root. */
 | 
			
		||||
      tty->fd = try_open_vt(tty, error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (tty->fd <= 0 && (!error || !*error))
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		   g_io_error_from_errno (errno),
 | 
			
		||||
		   "Could not open tty0: %s", strerror (errno));
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (ioctl(tty->fd, VT_GETSTATE, &vts) == 0)
 | 
			
		||||
    tty->starting_vt = vts.v_active;
 | 
			
		||||
  else
 | 
			
		||||
    tty->starting_vt = tty->vt;
 | 
			
		||||
  
 | 
			
		||||
  if (tty->starting_vt != tty->vt)
 | 
			
		||||
    {
 | 
			
		||||
      if (ioctl(tty->fd, VT_ACTIVATE, tty->vt) < 0 ||
 | 
			
		||||
	  ioctl(tty->fd, VT_WAITACTIVE, tty->vt) < 0)
 | 
			
		||||
	{
 | 
			
		||||
	  g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		       g_io_error_from_errno (errno),
 | 
			
		||||
		       "Failed to switch to new vt: %s", strerror (errno));
 | 
			
		||||
	  goto err;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (tcgetattr(tty->fd, &tty->terminal_attributes) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		   g_io_error_from_errno (errno),
 | 
			
		||||
		   "Could not get terminal attributes: %s", strerror (errno));
 | 
			
		||||
      goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Ignore control characters and disable echo */
 | 
			
		||||
  raw_attributes = tty->terminal_attributes;
 | 
			
		||||
  cfmakeraw(&raw_attributes);
 | 
			
		||||
 | 
			
		||||
  /* Fix up line endings to be normal (cfmakeraw hoses them) */
 | 
			
		||||
  raw_attributes.c_oflag |= OPOST | OCRNL;
 | 
			
		||||
  /* Don't generate ttou signals */
 | 
			
		||||
  raw_attributes.c_oflag &= ~TOSTOP;
 | 
			
		||||
 | 
			
		||||
  if (tcsetattr(tty->fd, TCSANOW, &raw_attributes) < 0)
 | 
			
		||||
    g_warning("Could not put terminal into raw mode: %s", strerror (errno));
 | 
			
		||||
 | 
			
		||||
  ioctl(tty->fd, KDGKBMODE, &tty->kb_mode);
 | 
			
		||||
  ret = ioctl(tty->fd, KDSKBMODE, K_OFF);
 | 
			
		||||
  if (ret)
 | 
			
		||||
    {
 | 
			
		||||
      ret = ioctl(tty->fd, KDSKBMODE, K_RAW);
 | 
			
		||||
      if (ret)
 | 
			
		||||
	{
 | 
			
		||||
	  g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		       g_io_error_from_errno (errno),
 | 
			
		||||
		       "Failed to set keyboard mode: %s", strerror (errno));
 | 
			
		||||
	  goto err_attr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      tty->input_source = g_unix_fd_add (tty->fd,
 | 
			
		||||
					 G_IO_IN,
 | 
			
		||||
					 on_tty_input, tty);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS);
 | 
			
		||||
  if (ret)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		   g_io_error_from_errno (errno),
 | 
			
		||||
		   "Failed to set KD_GRAPHICS mode: %s", strerror (errno));
 | 
			
		||||
      goto err_kdkbmode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  mode.mode = VT_PROCESS;
 | 
			
		||||
  mode.relsig = SIGUSR1;
 | 
			
		||||
  mode.acqsig = SIGUSR2;
 | 
			
		||||
  if (ioctl(tty->fd, VT_SETMODE, &mode) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error, G_IO_ERROR,
 | 
			
		||||
		   g_io_error_from_errno (errno),
 | 
			
		||||
		   "Failed to take control of vt handling: %s", strerror (errno));
 | 
			
		||||
      goto err_kdmode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  tty->vt_leave_source = g_unix_signal_source_new (SIGUSR1);
 | 
			
		||||
  g_source_set_callback (tty->vt_leave_source, vt_release_handler, tty, NULL);
 | 
			
		||||
 | 
			
		||||
  tty->vt_enter_source = g_unix_signal_source_new (SIGUSR2);
 | 
			
		||||
  g_source_set_callback (tty->vt_enter_source, quit_nested_loop, tty, NULL);
 | 
			
		||||
  tty->nested_term = g_unix_signal_source_new (SIGTERM);
 | 
			
		||||
  g_source_set_callback (tty->nested_term, quit_nested_loop, tty, NULL);
 | 
			
		||||
 | 
			
		||||
  tty->nested_context = g_main_context_new ();
 | 
			
		||||
  tty->nested_loop = g_main_loop_new (tty->nested_context, FALSE);
 | 
			
		||||
 | 
			
		||||
  g_source_attach (tty->vt_leave_source, NULL);
 | 
			
		||||
  g_source_attach (tty->vt_enter_source, tty->nested_context);
 | 
			
		||||
  g_source_attach (tty->nested_term, tty->nested_context);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
 err_kdmode:
 | 
			
		||||
  ioctl (tty->fd, KDSETMODE, KD_TEXT);
 | 
			
		||||
 | 
			
		||||
 err_kdkbmode:
 | 
			
		||||
  if (tty->input_source)
 | 
			
		||||
    g_source_remove (tty->input_source);
 | 
			
		||||
  ioctl (tty->fd, KDSKBMODE, tty->kb_mode);
 | 
			
		||||
 | 
			
		||||
 err_attr:
 | 
			
		||||
  tcsetattr (tty->fd, TCSANOW, &tty->terminal_attributes);
 | 
			
		||||
  
 | 
			
		||||
 err:
 | 
			
		||||
  close (tty->fd);
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_tty_reset (MetaTTY  *tty,
 | 
			
		||||
		gboolean  warn_if_fail)
 | 
			
		||||
{
 | 
			
		||||
  struct vt_mode mode = { 0 };
 | 
			
		||||
 | 
			
		||||
  if (ioctl (tty->fd, KDSKBMODE, tty->kb_mode) && warn_if_fail)
 | 
			
		||||
    g_warning ("failed to restore keyboard mode: %s", strerror (errno));
 | 
			
		||||
 | 
			
		||||
  if (ioctl (tty->fd, KDSETMODE, KD_TEXT) && warn_if_fail)
 | 
			
		||||
    g_warning ("failed to set KD_TEXT mode on tty: %s", strerror (errno));
 | 
			
		||||
 | 
			
		||||
  if (tcsetattr (tty->fd, TCSANOW, &tty->terminal_attributes) < 0 && warn_if_fail)
 | 
			
		||||
    g_warning ("could not restore terminal to canonical mode");
 | 
			
		||||
 | 
			
		||||
  mode.mode = VT_AUTO;
 | 
			
		||||
  if (ioctl (tty->fd, VT_SETMODE, &mode) < 0 && warn_if_fail)
 | 
			
		||||
    g_warning ("could not reset vt handling\n");
 | 
			
		||||
 | 
			
		||||
  if (tty->vt != tty->starting_vt)
 | 
			
		||||
    {
 | 
			
		||||
      ioctl(tty->fd, VT_ACTIVATE, tty->starting_vt);
 | 
			
		||||
      ioctl(tty->fd, VT_WAITACTIVE, tty->starting_vt);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_tty_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaTTY *tty = META_TTY (object);
 | 
			
		||||
 | 
			
		||||
  if (tty->input_source)
 | 
			
		||||
    g_source_remove (tty->input_source);
 | 
			
		||||
 | 
			
		||||
  g_source_destroy (tty->vt_enter_source);
 | 
			
		||||
  g_source_destroy (tty->vt_leave_source);
 | 
			
		||||
  g_source_destroy (tty->nested_term);
 | 
			
		||||
 | 
			
		||||
  g_main_loop_unref (tty->nested_loop);
 | 
			
		||||
  g_main_context_unref (tty->nested_context);
 | 
			
		||||
 | 
			
		||||
  meta_tty_reset (tty, TRUE);
 | 
			
		||||
 | 
			
		||||
  close (tty->fd);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_tty_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_tty_init (MetaTTY *self)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_tty_class_init (MetaTTYClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_tty_finalize;
 | 
			
		||||
 | 
			
		||||
  signals[SIGNAL_ENTER] = g_signal_new ("enter",
 | 
			
		||||
					G_TYPE_FROM_CLASS (klass),
 | 
			
		||||
					G_SIGNAL_RUN_FIRST,
 | 
			
		||||
					0, /* class offset */
 | 
			
		||||
					NULL, NULL, /* accumulator */
 | 
			
		||||
					g_cclosure_marshal_VOID__VOID,
 | 
			
		||||
					G_TYPE_NONE, 0);
 | 
			
		||||
 | 
			
		||||
  signals[SIGNAL_LEAVE] = g_signal_new ("leave",
 | 
			
		||||
					G_TYPE_FROM_CLASS (klass),
 | 
			
		||||
					G_SIGNAL_RUN_FIRST,
 | 
			
		||||
					0, /* class offset */
 | 
			
		||||
					NULL, NULL, /* accumulator */
 | 
			
		||||
					g_cclosure_marshal_VOID__VOID,
 | 
			
		||||
					G_TYPE_NONE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_tty_initable_iface_init (GInitableIface *iface)
 | 
			
		||||
{
 | 
			
		||||
  iface->init = meta_tty_initable_init;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaTTY *
 | 
			
		||||
meta_tty_new (void)
 | 
			
		||||
{
 | 
			
		||||
  GError *error;
 | 
			
		||||
  MetaTTY *tty;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  tty = g_initable_new (META_TYPE_TTY, NULL, &error, NULL);
 | 
			
		||||
 | 
			
		||||
  if (tty == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Failed to initalize TTY handling: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return tty;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								src/wayland/meta-tty.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/wayland/meta-tty.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_TTY_H
 | 
			
		||||
#define META_TTY_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_TTY              (meta_tty_get_type())
 | 
			
		||||
#define META_TTY(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_TTY, MetaTTY))
 | 
			
		||||
#define META_TTY_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_TTY, MetaTTYClass))
 | 
			
		||||
#define META_IS_TTY(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_TTY))
 | 
			
		||||
#define META_IS_TTY_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_TTY))
 | 
			
		||||
#define META_TTY_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TTY, MetaTTYClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaTTY      MetaTTY;
 | 
			
		||||
typedef struct _MetaTTYClass MetaTTYClass;
 | 
			
		||||
 | 
			
		||||
GType             meta_tty_get_type                (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
MetaTTY          *meta_tty_new                     (void);
 | 
			
		||||
 | 
			
		||||
gboolean          meta_tty_activate_vt             (MetaTTY  *self,
 | 
			
		||||
						    int       number,
 | 
			
		||||
						    GError  **error);
 | 
			
		||||
 | 
			
		||||
void              meta_tty_reset                   (MetaTTY  *self,
 | 
			
		||||
						    gboolean  warn_if_fail);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* META_TTY_H */
 | 
			
		||||
							
								
								
									
										548
									
								
								src/wayland/meta-wayland-data-device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										548
									
								
								src/wayland/meta-wayland-data-device.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,548 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2011 Kristian Høgsberg
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
			
		||||
 * documentation for any purpose is hereby granted without fee, provided that
 | 
			
		||||
 * the above copyright notice appear in all copies and that both that copyright
 | 
			
		||||
 * notice and this permission notice appear in supporting documentation, and
 | 
			
		||||
 * that the name of the copyright holders not be used in advertising or
 | 
			
		||||
 * publicity pertaining to distribution of the software without specific,
 | 
			
		||||
 * written prior permission.  The copyright holders make no representations
 | 
			
		||||
 * about the suitability of this software for any purpose.  It is provided "as
 | 
			
		||||
 * is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
			
		||||
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
			
		||||
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
			
		||||
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
			
		||||
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
			
		||||
 * OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* The file is based on src/data-device.c from Weston */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-data-device.h"
 | 
			
		||||
#include "meta-wayland-seat.h"
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_accept (struct wl_client *client,
 | 
			
		||||
                   struct wl_resource *resource,
 | 
			
		||||
                   guint32 serial,
 | 
			
		||||
                   const char *mime_type)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Check that client is currently focused by the input
 | 
			
		||||
   * device that is currently dragging this data source.  Should
 | 
			
		||||
   * this be a wl_data_device request? */
 | 
			
		||||
 | 
			
		||||
  if (offer->source)
 | 
			
		||||
    offer->source->accept (offer->source, serial, mime_type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_receive (struct wl_client *client, struct wl_resource *resource,
 | 
			
		||||
                    const char *mime_type, int32_t fd)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  if (offer->source)
 | 
			
		||||
    offer->source->send (offer->source, mime_type, fd);
 | 
			
		||||
  else
 | 
			
		||||
    close (fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_destroy (struct wl_client *client, struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_data_offer_interface data_offer_interface = {
 | 
			
		||||
  data_offer_accept,
 | 
			
		||||
  data_offer_receive,
 | 
			
		||||
  data_offer_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_data_offer (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  if (offer->source)
 | 
			
		||||
    wl_list_remove (&offer->source_destroy_listener.link);
 | 
			
		||||
  free (offer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_offer_data_source (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer;
 | 
			
		||||
 | 
			
		||||
  offer = wl_container_of (listener, offer, source_destroy_listener);
 | 
			
		||||
 | 
			
		||||
  offer->source = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wl_resource *
 | 
			
		||||
meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
 | 
			
		||||
                                     struct wl_resource *target)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer;
 | 
			
		||||
  char **p;
 | 
			
		||||
 | 
			
		||||
  offer = malloc (sizeof *offer);
 | 
			
		||||
  if (offer == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  offer->source = source;
 | 
			
		||||
  offer->source_destroy_listener.notify = destroy_offer_data_source;
 | 
			
		||||
 | 
			
		||||
  offer->resource = wl_client_add_object (wl_resource_get_client (target),
 | 
			
		||||
                                          &wl_data_offer_interface,
 | 
			
		||||
                                          &data_offer_interface,
 | 
			
		||||
                                          0,
 | 
			
		||||
                                          offer);
 | 
			
		||||
  wl_resource_set_destructor (offer->resource, destroy_data_offer);
 | 
			
		||||
  wl_resource_add_destroy_listener (source->resource,
 | 
			
		||||
                                    &offer->source_destroy_listener);
 | 
			
		||||
 | 
			
		||||
  wl_data_device_send_data_offer (target, offer->resource);
 | 
			
		||||
 | 
			
		||||
  wl_array_for_each (p, &source->mime_types)
 | 
			
		||||
    wl_data_offer_send_offer (offer->resource, *p);
 | 
			
		||||
 | 
			
		||||
  return offer->resource;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_source_offer (struct wl_client *client,
 | 
			
		||||
                   struct wl_resource *resource, const char *type)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
 | 
			
		||||
  char **p;
 | 
			
		||||
 | 
			
		||||
  p = wl_array_add (&source->mime_types, sizeof *p);
 | 
			
		||||
  if (p)
 | 
			
		||||
    *p = strdup (type);
 | 
			
		||||
  if (!p || !*p)
 | 
			
		||||
    wl_resource_post_no_memory (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_source_destroy (struct wl_client *client, struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wl_data_source_interface data_source_interface = {
 | 
			
		||||
  data_source_offer,
 | 
			
		||||
  data_source_destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_drag_focus (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (listener, seat, drag_focus_listener);
 | 
			
		||||
 | 
			
		||||
  seat->drag_focus_resource = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drag_grab_focus (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                 MetaWaylandSurface *surface,
 | 
			
		||||
                 wl_fixed_t x,
 | 
			
		||||
                 wl_fixed_t y)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
 | 
			
		||||
  struct wl_resource *resource, *offer = NULL;
 | 
			
		||||
  struct wl_display *display;
 | 
			
		||||
  guint32 serial;
 | 
			
		||||
 | 
			
		||||
  if (seat->drag_focus_resource)
 | 
			
		||||
    {
 | 
			
		||||
      wl_data_device_send_leave (seat->drag_focus_resource);
 | 
			
		||||
      wl_list_remove (&seat->drag_focus_listener.link);
 | 
			
		||||
      seat->drag_focus_resource = NULL;
 | 
			
		||||
      seat->drag_focus = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (!seat->drag_data_source &&
 | 
			
		||||
      wl_resource_get_client (surface->resource) != seat->drag_client)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  resource =
 | 
			
		||||
    wl_resource_find_for_client (&seat->drag_resource_list,
 | 
			
		||||
                                 wl_resource_get_client (surface->resource));
 | 
			
		||||
  if (!resource)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  display = wl_client_get_display (wl_resource_get_client (resource));
 | 
			
		||||
  serial = wl_display_next_serial (display);
 | 
			
		||||
 | 
			
		||||
  if (seat->drag_data_source)
 | 
			
		||||
    offer = meta_wayland_data_source_send_offer (seat->drag_data_source,
 | 
			
		||||
                                                 resource);
 | 
			
		||||
 | 
			
		||||
  wl_data_device_send_enter (resource, serial, surface->resource,
 | 
			
		||||
                             x, y, offer);
 | 
			
		||||
 | 
			
		||||
  seat->drag_focus = surface;
 | 
			
		||||
  seat->drag_focus_listener.notify = destroy_drag_focus;
 | 
			
		||||
  wl_resource_add_destroy_listener (resource, &seat->drag_focus_listener);
 | 
			
		||||
  seat->drag_focus_resource = resource;
 | 
			
		||||
  grab->focus = surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drag_grab_motion (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                  guint32 time, wl_fixed_t x, wl_fixed_t y)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
 | 
			
		||||
 | 
			
		||||
  if (seat->drag_focus_resource)
 | 
			
		||||
    wl_data_device_send_motion (seat->drag_focus_resource, time, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_device_end_drag_grab (MetaWaylandSeat *seat)
 | 
			
		||||
{
 | 
			
		||||
  if (seat->drag_surface)
 | 
			
		||||
    {
 | 
			
		||||
      seat->drag_surface = NULL;
 | 
			
		||||
      wl_signal_emit (&seat->drag_icon_signal, NULL);
 | 
			
		||||
      wl_list_remove (&seat->drag_icon_listener.link);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  drag_grab_focus (&seat->drag_grab, NULL,
 | 
			
		||||
                   wl_fixed_from_int (0), wl_fixed_from_int (0));
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_end_grab (&seat->pointer);
 | 
			
		||||
 | 
			
		||||
  seat->drag_data_source = NULL;
 | 
			
		||||
  seat->drag_client = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drag_grab_button (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                  guint32 time, guint32 button, guint32 state_w)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
 | 
			
		||||
  enum wl_pointer_button_state state = state_w;
 | 
			
		||||
 | 
			
		||||
  if (seat->drag_focus_resource &&
 | 
			
		||||
      seat->pointer.grab_button == button &&
 | 
			
		||||
      state == WL_POINTER_BUTTON_STATE_RELEASED)
 | 
			
		||||
    wl_data_device_send_drop (seat->drag_focus_resource);
 | 
			
		||||
 | 
			
		||||
  if (seat->pointer.button_count == 0 &&
 | 
			
		||||
      state == WL_POINTER_BUTTON_STATE_RELEASED)
 | 
			
		||||
    {
 | 
			
		||||
      if (seat->drag_data_source)
 | 
			
		||||
        wl_list_remove (&seat->drag_data_source_listener.link);
 | 
			
		||||
      data_device_end_drag_grab (seat);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandPointerGrabInterface drag_grab_interface = {
 | 
			
		||||
  drag_grab_focus,
 | 
			
		||||
  drag_grab_motion,
 | 
			
		||||
  drag_grab_button,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_data_device_source (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat =
 | 
			
		||||
    wl_container_of (listener, seat, drag_data_source_listener);
 | 
			
		||||
 | 
			
		||||
  data_device_end_drag_grab (seat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_data_device_icon (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat =
 | 
			
		||||
    wl_container_of (listener, seat, drag_icon_listener);
 | 
			
		||||
 | 
			
		||||
  seat->drag_surface = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_device_start_drag (struct wl_client *client,
 | 
			
		||||
                        struct wl_resource *resource,
 | 
			
		||||
                        struct wl_resource *source_resource,
 | 
			
		||||
                        struct wl_resource *origin_resource,
 | 
			
		||||
                        struct wl_resource *icon_resource, guint32 serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Check that client has implicit grab on the origin
 | 
			
		||||
   * surface that matches the given time. */
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Check that the data source type array isn't empty. */
 | 
			
		||||
 | 
			
		||||
  seat->drag_grab.interface = &drag_grab_interface;
 | 
			
		||||
 | 
			
		||||
  seat->drag_client = client;
 | 
			
		||||
  seat->drag_data_source = NULL;
 | 
			
		||||
 | 
			
		||||
  if (source_resource)
 | 
			
		||||
    {
 | 
			
		||||
      seat->drag_data_source = wl_resource_get_user_data (source_resource);
 | 
			
		||||
      seat->drag_data_source_listener.notify = destroy_data_device_source;
 | 
			
		||||
      wl_resource_add_destroy_listener (source_resource,
 | 
			
		||||
                                        &seat->drag_data_source_listener);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (icon_resource)
 | 
			
		||||
    {
 | 
			
		||||
      seat->drag_surface = wl_resource_get_user_data (icon_resource);
 | 
			
		||||
      seat->drag_icon_listener.notify = destroy_data_device_icon;
 | 
			
		||||
      wl_resource_add_destroy_listener (icon_resource,
 | 
			
		||||
                                        &seat->drag_icon_listener);
 | 
			
		||||
      wl_signal_emit (&seat->drag_icon_signal, icon_resource);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_set_focus (&seat->pointer, NULL,
 | 
			
		||||
                              wl_fixed_from_int (0),
 | 
			
		||||
                              wl_fixed_from_int (0));
 | 
			
		||||
  meta_wayland_pointer_start_grab (&seat->pointer, &seat->drag_grab);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_selection_data_source (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat =
 | 
			
		||||
    wl_container_of (listener, seat, selection_data_source_listener);
 | 
			
		||||
  struct wl_resource *data_device;
 | 
			
		||||
  struct wl_resource *focus = NULL;
 | 
			
		||||
 | 
			
		||||
  seat->selection_data_source = NULL;
 | 
			
		||||
 | 
			
		||||
  focus = seat->keyboard.focus_resource;
 | 
			
		||||
 | 
			
		||||
  if (focus)
 | 
			
		||||
    {
 | 
			
		||||
      data_device =
 | 
			
		||||
        wl_resource_find_for_client (&seat->drag_resource_list,
 | 
			
		||||
                                     wl_resource_get_client (focus));
 | 
			
		||||
      if (data_device)
 | 
			
		||||
        wl_data_device_send_selection (data_device, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  wl_signal_emit (&seat->selection_signal, seat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
 | 
			
		||||
                                 MetaWaylandDataSource *source,
 | 
			
		||||
                                 guint32 serial)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *data_device, *offer;
 | 
			
		||||
  struct wl_resource *focus = NULL;
 | 
			
		||||
 | 
			
		||||
  if (seat->selection_data_source &&
 | 
			
		||||
      seat->selection_serial - serial < UINT32_MAX / 2)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (seat->selection_data_source)
 | 
			
		||||
    {
 | 
			
		||||
      seat->selection_data_source->cancel (seat->selection_data_source);
 | 
			
		||||
      wl_list_remove (&seat->selection_data_source_listener.link);
 | 
			
		||||
      seat->selection_data_source = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  seat->selection_data_source = source;
 | 
			
		||||
  seat->selection_serial = serial;
 | 
			
		||||
 | 
			
		||||
  focus = seat->keyboard.focus_resource;
 | 
			
		||||
 | 
			
		||||
  if (focus)
 | 
			
		||||
    {
 | 
			
		||||
      data_device =
 | 
			
		||||
        wl_resource_find_for_client (&seat->drag_resource_list,
 | 
			
		||||
                                     wl_resource_get_client (focus));
 | 
			
		||||
      if (data_device && source)
 | 
			
		||||
        {
 | 
			
		||||
          offer =
 | 
			
		||||
            meta_wayland_data_source_send_offer (seat->selection_data_source,
 | 
			
		||||
                                                 data_device);
 | 
			
		||||
          wl_data_device_send_selection (data_device, offer);
 | 
			
		||||
        }
 | 
			
		||||
      else if (data_device)
 | 
			
		||||
        {
 | 
			
		||||
          wl_data_device_send_selection (data_device, NULL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  wl_signal_emit (&seat->selection_signal, seat);
 | 
			
		||||
 | 
			
		||||
  if (source)
 | 
			
		||||
    {
 | 
			
		||||
      seat->selection_data_source_listener.notify =
 | 
			
		||||
        destroy_selection_data_source;
 | 
			
		||||
      wl_resource_add_destroy_listener (source->resource,
 | 
			
		||||
                                        &seat->selection_data_source_listener);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_device_set_selection (struct wl_client *client,
 | 
			
		||||
                           struct wl_resource *resource,
 | 
			
		||||
                           struct wl_resource *source_resource,
 | 
			
		||||
                           guint32 serial)
 | 
			
		||||
{
 | 
			
		||||
  if (!source_resource)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Store serial and check against incoming serial here. */
 | 
			
		||||
  meta_wayland_seat_set_selection (wl_resource_get_user_data (resource),
 | 
			
		||||
                                   wl_resource_get_user_data (source_resource),
 | 
			
		||||
                                   serial);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_data_device_interface data_device_interface = {
 | 
			
		||||
  data_device_start_drag,
 | 
			
		||||
  data_device_set_selection,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_data_source (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSource *source = wl_container_of (resource, source, resource);
 | 
			
		||||
  char **p;
 | 
			
		||||
 | 
			
		||||
  wl_array_for_each (p, &source->mime_types) free (*p);
 | 
			
		||||
 | 
			
		||||
  wl_array_release (&source->mime_types);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
client_source_accept (MetaWaylandDataSource *source,
 | 
			
		||||
                      guint32 time, const char *mime_type)
 | 
			
		||||
{
 | 
			
		||||
  wl_data_source_send_target (source->resource, mime_type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
client_source_send (MetaWaylandDataSource *source,
 | 
			
		||||
                    const char *mime_type, int32_t fd)
 | 
			
		||||
{
 | 
			
		||||
  wl_data_source_send_send (source->resource, mime_type, fd);
 | 
			
		||||
  close (fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
client_source_cancel (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  wl_data_source_send_cancelled (source->resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
create_data_source (struct wl_client *client,
 | 
			
		||||
                    struct wl_resource *resource, guint32 id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSource *source;
 | 
			
		||||
 | 
			
		||||
  source = malloc (sizeof *source);
 | 
			
		||||
  if (source == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_no_memory (resource);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  source->resource = wl_client_add_object (client,
 | 
			
		||||
                                           &wl_data_source_interface,
 | 
			
		||||
                                           &data_source_interface,
 | 
			
		||||
                                           id,
 | 
			
		||||
                                           source);
 | 
			
		||||
  wl_resource_set_destructor (source->resource, destroy_data_source);
 | 
			
		||||
 | 
			
		||||
  source->accept = client_source_accept;
 | 
			
		||||
  source->send = client_source_send;
 | 
			
		||||
  source->cancel = client_source_cancel;
 | 
			
		||||
 | 
			
		||||
  wl_array_init (&source->mime_types);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
unbind_data_device (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_list_remove (wl_resource_get_link (resource));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
get_data_device (struct wl_client *client,
 | 
			
		||||
                 struct wl_resource *manager_resource,
 | 
			
		||||
                 guint32 id, struct wl_resource *seat_resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  resource = wl_client_add_object (client, &wl_data_device_interface,
 | 
			
		||||
                                   &data_device_interface, id, seat);
 | 
			
		||||
 | 
			
		||||
  wl_list_insert (&seat->drag_resource_list, wl_resource_get_link (resource));
 | 
			
		||||
  wl_resource_set_destructor (resource, unbind_data_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_data_device_manager_interface manager_interface = {
 | 
			
		||||
  create_data_source,
 | 
			
		||||
  get_data_device
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bind_manager (struct wl_client *client,
 | 
			
		||||
              void *data, guint32 version, guint32 id)
 | 
			
		||||
{
 | 
			
		||||
  wl_client_add_object (client, &wl_data_device_manager_interface,
 | 
			
		||||
                        &manager_interface, id, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *data_device, *focus, *offer;
 | 
			
		||||
  MetaWaylandDataSource *source;
 | 
			
		||||
 | 
			
		||||
  focus = seat->keyboard.focus_resource;
 | 
			
		||||
  if (!focus)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  data_device = wl_resource_find_for_client (&seat->drag_resource_list,
 | 
			
		||||
                                             wl_resource_get_client (focus));
 | 
			
		||||
  if (!data_device)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  source = seat->selection_data_source;
 | 
			
		||||
  if (source)
 | 
			
		||||
    {
 | 
			
		||||
      offer = meta_wayland_data_source_send_offer (source, data_device);
 | 
			
		||||
      wl_data_device_send_selection (data_device, offer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_wayland_data_device_manager_init (struct wl_display *display)
 | 
			
		||||
{
 | 
			
		||||
  if (wl_display_add_global (display,
 | 
			
		||||
                             &wl_data_device_manager_interface,
 | 
			
		||||
                             NULL, bind_manager) == NULL)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/wayland/meta-wayland-data-device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/wayland/meta-wayland-data-device.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2008 Kristian Høgsberg
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
			
		||||
 * documentation for any purpose is hereby granted without fee, provided that
 | 
			
		||||
 * the above copyright notice appear in all copies and that both that copyright
 | 
			
		||||
 * notice and this permission notice appear in supporting documentation, and
 | 
			
		||||
 * that the name of the copyright holders not be used in advertising or
 | 
			
		||||
 * publicity pertaining to distribution of the software without specific,
 | 
			
		||||
 * written prior permission.  The copyright holders make no representations
 | 
			
		||||
 * about the suitability of this software for any purpose.  It is provided "as
 | 
			
		||||
 * is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
			
		||||
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
			
		||||
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
			
		||||
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
			
		||||
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
			
		||||
 * OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __META_WAYLAND_DATA_DEVICE_H__
 | 
			
		||||
#define __META_WAYLAND_DATA_DEVICE_H__
 | 
			
		||||
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-seat.h"
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_wayland_data_device_manager_init (struct wl_display *display);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
 | 
			
		||||
                                 MetaWaylandDataSource *source,
 | 
			
		||||
                                 uint32_t serial);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* __META_WAYLAND_DATA_DEVICE_H__ */
 | 
			
		||||
							
								
								
									
										618
									
								
								src/wayland/meta-wayland-keyboard.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										618
									
								
								src/wayland/meta-wayland-keyboard.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,618 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2010-2011 Intel Corporation
 | 
			
		||||
 * Copyright © 2008-2011 Kristian Høgsberg
 | 
			
		||||
 * Copyright © 2012 Collabora, Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* The file is based on src/input.c from Weston */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <clutter/evdev/clutter-evdev.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-keyboard.h"
 | 
			
		||||
 | 
			
		||||
static MetaWaylandSeat *
 | 
			
		||||
meta_wayland_keyboard_get_seat (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (keyboard, seat, keyboard);
 | 
			
		||||
 | 
			
		||||
  return seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
create_anonymous_file (off_t size,
 | 
			
		||||
                       GError **error)
 | 
			
		||||
{
 | 
			
		||||
  static const char template[] = "mutter-shared-XXXXXX";
 | 
			
		||||
  char *path;
 | 
			
		||||
  int fd, flags;
 | 
			
		||||
 | 
			
		||||
  fd = g_file_open_tmp (template, &path, error);
 | 
			
		||||
 | 
			
		||||
  if (fd == -1)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  unlink (path);
 | 
			
		||||
  g_free (path);
 | 
			
		||||
 | 
			
		||||
  flags = fcntl (fd, F_GETFD);
 | 
			
		||||
  if (flags == -1)
 | 
			
		||||
    goto err;
 | 
			
		||||
 | 
			
		||||
  if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
 | 
			
		||||
    goto err;
 | 
			
		||||
 | 
			
		||||
  if (ftruncate (fd, size) < 0)
 | 
			
		||||
    goto err;
 | 
			
		||||
 | 
			
		||||
  return fd;
 | 
			
		||||
 | 
			
		||||
 err:
 | 
			
		||||
  g_set_error_literal (error,
 | 
			
		||||
                       G_FILE_ERROR,
 | 
			
		||||
                       g_file_error_from_errno (errno),
 | 
			
		||||
                       strerror (errno));
 | 
			
		||||
  close (fd);
 | 
			
		||||
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  char *keymap_str;
 | 
			
		||||
 | 
			
		||||
  xkb_info->shift_mod =
 | 
			
		||||
    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
 | 
			
		||||
  xkb_info->caps_mod =
 | 
			
		||||
    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
 | 
			
		||||
  xkb_info->ctrl_mod =
 | 
			
		||||
    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
 | 
			
		||||
  xkb_info->alt_mod =
 | 
			
		||||
    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
 | 
			
		||||
  xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
 | 
			
		||||
  xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
 | 
			
		||||
  xkb_info->super_mod =
 | 
			
		||||
    xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
 | 
			
		||||
  xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
    }
 | 
			
		||||
  xkb_info->keymap_size = strlen (keymap_str) + 1;
 | 
			
		||||
 | 
			
		||||
  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",
 | 
			
		||||
                 (unsigned long) xkb_info->keymap_size,
 | 
			
		||||
                 error->message);
 | 
			
		||||
      g_clear_error (&error);
 | 
			
		||||
      goto err_keymap_str;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
 | 
			
		||||
                                PROT_READ | PROT_WRITE,
 | 
			
		||||
                                MAP_SHARED, xkb_info->keymap_fd, 0);
 | 
			
		||||
  if (xkb_info->keymap_area == MAP_FAILED)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("failed to mmap() %lu bytes\n",
 | 
			
		||||
                 (unsigned long) xkb_info->keymap_size);
 | 
			
		||||
      goto err_dev_zero;
 | 
			
		||||
    }
 | 
			
		||||
  strcpy (xkb_info->keymap_area, keymap_str);
 | 
			
		||||
  free (keymap_str);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
lose_keyboard_focus (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboard *keyboard =
 | 
			
		||||
    wl_container_of (listener, keyboard, focus_listener);
 | 
			
		||||
 | 
			
		||||
  keyboard->focus_resource = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_grab_key (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                  uint32_t time, uint32_t key, uint32_t state)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboard *keyboard = grab->keyboard;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  uint32_t serial;
 | 
			
		||||
 | 
			
		||||
  resource = keyboard->focus_resource;
 | 
			
		||||
  if (resource)
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
      wl_keyboard_send_key (resource, serial, time, key, state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wl_resource *
 | 
			
		||||
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_client *client;
 | 
			
		||||
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  if (!surface->resource)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  client = wl_resource_get_client (surface->resource);
 | 
			
		||||
 | 
			
		||||
  return wl_resource_find_for_client (list, client);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
 | 
			
		||||
                        uint32_t mods_depressed, uint32_t mods_latched,
 | 
			
		||||
                        uint32_t mods_locked, uint32_t group)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboard *keyboard = grab->keyboard;
 | 
			
		||||
  MetaWaylandSeat *seat = meta_wayland_keyboard_get_seat (keyboard);
 | 
			
		||||
  MetaWaylandPointer *pointer = &seat->pointer;
 | 
			
		||||
  struct wl_resource *resource, *pr;
 | 
			
		||||
 | 
			
		||||
  resource = keyboard->focus_resource;
 | 
			
		||||
  if (!resource)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  wl_keyboard_send_modifiers (resource, serial, mods_depressed,
 | 
			
		||||
                              mods_latched, mods_locked, group);
 | 
			
		||||
 | 
			
		||||
  if (pointer && pointer->focus && pointer->focus != keyboard->focus)
 | 
			
		||||
    {
 | 
			
		||||
      pr = find_resource_for_surface (&keyboard->resource_list,
 | 
			
		||||
                                      pointer->focus);
 | 
			
		||||
      if (pr)
 | 
			
		||||
        {
 | 
			
		||||
          wl_keyboard_send_modifiers (pr, serial,
 | 
			
		||||
				      mods_depressed,
 | 
			
		||||
                                      mods_latched,
 | 
			
		||||
                                      mods_locked,
 | 
			
		||||
                                      group);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandKeyboardGrabInterface
 | 
			
		||||
  default_keyboard_grab_interface = {
 | 
			
		||||
  default_grab_key,
 | 
			
		||||
  default_grab_modifiers,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                            struct wl_display   *display,
 | 
			
		||||
			    gboolean             is_evdev)
 | 
			
		||||
{
 | 
			
		||||
  ClutterDeviceManager *manager;
 | 
			
		||||
 | 
			
		||||
  memset (keyboard, 0, sizeof *keyboard);
 | 
			
		||||
 | 
			
		||||
  wl_list_init (&keyboard->resource_list);
 | 
			
		||||
  wl_array_init (&keyboard->keys);
 | 
			
		||||
  keyboard->focus_listener.notify = lose_keyboard_focus;
 | 
			
		||||
  keyboard->default_grab.interface = &default_keyboard_grab_interface;
 | 
			
		||||
  keyboard->default_grab.keyboard = keyboard;
 | 
			
		||||
  keyboard->grab = &keyboard->default_grab;
 | 
			
		||||
  wl_signal_init (&keyboard->focus_signal);
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
      keyboard->xkb_state = clutter_evdev_get_keyboard_state (manager);
 | 
			
		||||
      xkb_state_ref (keyboard->xkb_state);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      keyboard->xkb_state = xkb_state_new (keyboard->xkb_info.keymap);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
 | 
			
		||||
{
 | 
			
		||||
  if (xkb_info->keymap)
 | 
			
		||||
    xkb_map_unref (xkb_info->keymap);
 | 
			
		||||
 | 
			
		||||
  if (xkb_info->keymap_area)
 | 
			
		||||
    munmap (xkb_info->keymap_area, xkb_info->keymap_size);
 | 
			
		||||
  if (xkb_info->keymap_fd >= 0)
 | 
			
		||||
    close (xkb_info->keymap_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_state_from_clutter (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
			   ClutterModifierType  modifier_state)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t depressed_mods = 0;
 | 
			
		||||
  uint32_t locked_mods = 0;
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_SHIFT_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_LOCK_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
 | 
			
		||||
    locked_mods |= (1 << keyboard->xkb_info.caps_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_CONTROL_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_MOD1_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_MOD2_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_MOD3_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_SUPER_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.super_mod);
 | 
			
		||||
 | 
			
		||||
  if ((modifier_state & CLUTTER_MOD5_MASK) &&
 | 
			
		||||
      keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
 | 
			
		||||
    depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
 | 
			
		||||
 | 
			
		||||
  xkb_state_update_mask (keyboard->xkb_state,
 | 
			
		||||
			 depressed_mods,
 | 
			
		||||
			 0,
 | 
			
		||||
			 locked_mods,
 | 
			
		||||
			 0, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
state_equal (MetaWaylandXkbState *one,
 | 
			
		||||
	     MetaWaylandXkbState *two)
 | 
			
		||||
{
 | 
			
		||||
  return one->mods_depressed == two->mods_depressed &&
 | 
			
		||||
    one->mods_latched == two->mods_latched &&
 | 
			
		||||
    one->mods_locked == two->mods_locked &&
 | 
			
		||||
    one->group == two->group;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_modifiers (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
               guint32 serial,
 | 
			
		||||
               ClutterModifierType modifier_state)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboardGrab *grab = keyboard->grab;
 | 
			
		||||
  MetaWaylandXkbState new_state;
 | 
			
		||||
 | 
			
		||||
  /* In the evdev case, the state is shared with the clutter backend, so
 | 
			
		||||
     we don't need to update it */
 | 
			
		||||
  if (!keyboard->is_evdev)
 | 
			
		||||
    update_state_from_clutter (keyboard, modifier_state);
 | 
			
		||||
 | 
			
		||||
  new_state.mods_depressed = xkb_state_serialize_mods (keyboard->xkb_state,
 | 
			
		||||
						       XKB_STATE_MODS_DEPRESSED);
 | 
			
		||||
  new_state.mods_latched = xkb_state_serialize_mods (keyboard->xkb_state,
 | 
			
		||||
						     XKB_STATE_MODS_LATCHED);
 | 
			
		||||
  new_state.mods_locked = xkb_state_serialize_mods (keyboard->xkb_state,
 | 
			
		||||
						    XKB_STATE_MODS_LOCKED);
 | 
			
		||||
  new_state.group = xkb_state_serialize_layout (keyboard->xkb_state,
 | 
			
		||||
						XKB_STATE_LAYOUT_EFFECTIVE);
 | 
			
		||||
 | 
			
		||||
  if (state_equal (&keyboard->modifier_state, &new_state))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  keyboard->modifier_state = new_state;
 | 
			
		||||
 | 
			
		||||
  grab->interface->modifiers (grab,
 | 
			
		||||
                              serial,
 | 
			
		||||
                              new_state.mods_depressed,
 | 
			
		||||
			      new_state.mods_latched,
 | 
			
		||||
			      new_state.mods_locked,
 | 
			
		||||
                              new_state.group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                    const ClutterKeyEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  gboolean state = event->type == CLUTTER_KEY_PRESS;
 | 
			
		||||
  guint evdev_code;
 | 
			
		||||
  uint32_t serial;
 | 
			
		||||
 | 
			
		||||
  /* We can't do anything with the event if we can't get an evdev
 | 
			
		||||
     keycode for it */
 | 
			
		||||
  if (event->device == NULL ||
 | 
			
		||||
      !clutter_input_device_keycode_to_evdev (event->device,
 | 
			
		||||
                                              event->hardware_keycode,
 | 
			
		||||
                                              &evdev_code))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* We want to ignore events that are sent because of auto-repeat. In
 | 
			
		||||
     the Clutter event stream these appear as a single key press
 | 
			
		||||
     event. We can detect that because the key will already have been
 | 
			
		||||
     pressed */
 | 
			
		||||
  if (state)
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t *end = (void *) ((char *) keyboard->keys.data +
 | 
			
		||||
                                keyboard->keys.size);
 | 
			
		||||
      uint32_t *k;
 | 
			
		||||
 | 
			
		||||
      /* Ignore the event if the key is already down */
 | 
			
		||||
      for (k = keyboard->keys.data; k < end; k++)
 | 
			
		||||
        if (*k == evdev_code)
 | 
			
		||||
          return;
 | 
			
		||||
 | 
			
		||||
      /* Otherwise add the key to the list of pressed keys */
 | 
			
		||||
      k = wl_array_add (&keyboard->keys, sizeof (*k));
 | 
			
		||||
      *k = evdev_code;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t *end = (void *) ((char *) keyboard->keys.data +
 | 
			
		||||
                                keyboard->keys.size);
 | 
			
		||||
      uint32_t *k;
 | 
			
		||||
 | 
			
		||||
      /* Remove the key from the array */
 | 
			
		||||
      for (k = keyboard->keys.data; k < end; k++)
 | 
			
		||||
        if (*k == evdev_code)
 | 
			
		||||
          {
 | 
			
		||||
            *k = *(end - 1);
 | 
			
		||||
            keyboard->keys.size -= sizeof (*k);
 | 
			
		||||
 | 
			
		||||
            goto found;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
      g_warning ("unexpected key release event for key 0x%x (%d)", evdev_code, event->keyval);
 | 
			
		||||
 | 
			
		||||
    found:
 | 
			
		||||
      (void) 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  serial = wl_display_next_serial (keyboard->display);
 | 
			
		||||
 | 
			
		||||
  set_modifiers (keyboard, serial, event->modifier_state);
 | 
			
		||||
 | 
			
		||||
  keyboard->grab->interface->key (keyboard->grab,
 | 
			
		||||
                                  event->time,
 | 
			
		||||
                                  evdev_code,
 | 
			
		||||
                                  state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                 MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  uint32_t serial;
 | 
			
		||||
 | 
			
		||||
  if (keyboard->focus_resource && keyboard->focus != surface)
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_display *display;
 | 
			
		||||
      struct wl_client *client;
 | 
			
		||||
 | 
			
		||||
      resource = keyboard->focus_resource;
 | 
			
		||||
      client = wl_resource_get_client (resource);
 | 
			
		||||
      display = wl_client_get_display (client);
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
      wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
 | 
			
		||||
      wl_list_remove (&keyboard->focus_listener.link);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  resource = find_resource_for_surface (&keyboard->resource_list, surface);
 | 
			
		||||
  if (resource &&
 | 
			
		||||
      (keyboard->focus != surface || keyboard->focus_resource != resource))
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (resource);
 | 
			
		||||
      struct wl_display *display;
 | 
			
		||||
 | 
			
		||||
      display = wl_client_get_display (client);
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
      wl_keyboard_send_modifiers (resource, serial,
 | 
			
		||||
                                  keyboard->modifier_state.mods_depressed,
 | 
			
		||||
                                  keyboard->modifier_state.mods_latched,
 | 
			
		||||
                                  keyboard->modifier_state.mods_locked,
 | 
			
		||||
                                  keyboard->modifier_state.group);
 | 
			
		||||
      wl_keyboard_send_enter (resource, serial, surface->resource,
 | 
			
		||||
                              &keyboard->keys);
 | 
			
		||||
      wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
 | 
			
		||||
      keyboard->focus_serial = serial;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  keyboard->focus_resource = resource;
 | 
			
		||||
  keyboard->focus = surface;
 | 
			
		||||
  wl_signal_emit (&keyboard->focus_signal, keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                  MetaWaylandKeyboardGrab *grab)
 | 
			
		||||
{
 | 
			
		||||
  keyboard->grab = grab;
 | 
			
		||||
  grab->keyboard = keyboard;
 | 
			
		||||
 | 
			
		||||
  /* XXX focus? */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  keyboard->grab = &keyboard->default_grab;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
  xkb_state_unref (keyboard->xkb_state);
 | 
			
		||||
 | 
			
		||||
  /* XXX: What about keyboard->resource_list? */
 | 
			
		||||
  if (keyboard->focus_resource)
 | 
			
		||||
    wl_list_remove (&keyboard->focus_listener.link);
 | 
			
		||||
  wl_array_release (&keyboard->keys);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
modal_key (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
	   uint32_t                 time,
 | 
			
		||||
	   uint32_t                 key,
 | 
			
		||||
	   uint32_t                 state)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
modal_modifiers (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
		 uint32_t                 serial,
 | 
			
		||||
		 uint32_t                 mods_depressed,
 | 
			
		||||
		 uint32_t                 mods_latched,
 | 
			
		||||
		 uint32_t                 mods_locked,
 | 
			
		||||
		 uint32_t                 group)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandKeyboardGrabInterface modal_grab = {
 | 
			
		||||
  modal_key,
 | 
			
		||||
  modal_modifiers,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboardGrab *grab;
 | 
			
		||||
 | 
			
		||||
  if (keyboard->grab != &keyboard->default_grab)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  grab = g_slice_new0 (MetaWaylandKeyboardGrab);
 | 
			
		||||
  grab->interface = &modal_grab;
 | 
			
		||||
  meta_wayland_keyboard_start_grab (keyboard, grab);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboardGrab *grab;
 | 
			
		||||
 | 
			
		||||
  grab = keyboard->grab;
 | 
			
		||||
 | 
			
		||||
  g_assert (grab->interface == &modal_grab);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_keyboard_end_grab (keyboard);
 | 
			
		||||
  g_slice_free (MetaWaylandKeyboardGrab, grab);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								src/wayland/meta-wayland-keyboard.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/wayland/meta-wayland-keyboard.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2008-2011 Kristian Høgsberg
 | 
			
		||||
 * Copyright © 2012 Collabora, Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __META_WAYLAND_KEYBOARD_H__
 | 
			
		||||
#define __META_WAYLAND_KEYBOARD_H__
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-seat.h"
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                            struct wl_display   *display,
 | 
			
		||||
			    gboolean             is_evdev);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                    const ClutterKeyEvent *event);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                 MetaWaylandSurface *surface);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
 | 
			
		||||
                                  MetaWaylandKeyboardGrab *grab);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard);
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_end_modal   (MetaWaylandKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
#endif /* __META_WAYLAND_KEYBOARD_H__ */
 | 
			
		||||
							
								
								
									
										326
									
								
								src/wayland/meta-wayland-pointer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								src/wayland/meta-wayland-pointer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,326 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2008 Kristian Høgsberg
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
			
		||||
 * documentation for any purpose is hereby granted without fee, provided that
 | 
			
		||||
 * the above copyright notice appear in all copies and that both that copyright
 | 
			
		||||
 * notice and this permission notice appear in supporting documentation, and
 | 
			
		||||
 * that the name of the copyright holders not be used in advertising or
 | 
			
		||||
 * publicity pertaining to distribution of the software without specific,
 | 
			
		||||
 * written prior permission.  The copyright holders make no representations
 | 
			
		||||
 * about the suitability of this software for any purpose.  It is provided "as
 | 
			
		||||
 * is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
			
		||||
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
			
		||||
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
			
		||||
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
			
		||||
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
			
		||||
 * OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* The file is based on src/input.c from Weston */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
static MetaWaylandSeat *
 | 
			
		||||
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
 | 
			
		||||
 | 
			
		||||
  return seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
lose_pointer_focus (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer =
 | 
			
		||||
    wl_container_of (listener, pointer, focus_listener);
 | 
			
		||||
 | 
			
		||||
  pointer->focus_resource = NULL;
 | 
			
		||||
  pointer->focus = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_grab_focus (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                    MetaWaylandSurface *surface,
 | 
			
		||||
                    wl_fixed_t x,
 | 
			
		||||
                    wl_fixed_t y)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = grab->pointer;
 | 
			
		||||
 | 
			
		||||
  if (pointer->button_count > 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_set_focus (pointer, surface, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_grab_motion (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                     uint32_t time, wl_fixed_t x, wl_fixed_t y)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  resource = grab->pointer->focus_resource;
 | 
			
		||||
  if (resource)
 | 
			
		||||
    wl_pointer_send_motion (resource, time, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_grab_button (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                     uint32_t time, uint32_t button, uint32_t state_w)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = grab->pointer;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  uint32_t serial;
 | 
			
		||||
  enum wl_pointer_button_state state = state_w;
 | 
			
		||||
 | 
			
		||||
  resource = pointer->focus_resource;
 | 
			
		||||
  if (resource)
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
      wl_pointer_send_button (resource, serial, time, button, state_w);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
 | 
			
		||||
    meta_wayland_pointer_set_focus (pointer, pointer->current,
 | 
			
		||||
                                pointer->current_x, pointer->current_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
 | 
			
		||||
  default_grab_focus,
 | 
			
		||||
  default_grab_motion,
 | 
			
		||||
  default_grab_button
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  memset (pointer, 0, sizeof *pointer);
 | 
			
		||||
  wl_list_init (&pointer->resource_list);
 | 
			
		||||
  pointer->focus_listener.notify = lose_pointer_focus;
 | 
			
		||||
  pointer->default_grab.interface = &default_pointer_grab_interface;
 | 
			
		||||
  pointer->default_grab.pointer = pointer;
 | 
			
		||||
  pointer->grab = &pointer->default_grab;
 | 
			
		||||
  wl_signal_init (&pointer->focus_signal);
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Pick better co-ords. */
 | 
			
		||||
  pointer->x = wl_fixed_from_int (100);
 | 
			
		||||
  pointer->y = wl_fixed_from_int (100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  /* XXX: What about pointer->resource_list? */
 | 
			
		||||
  if (pointer->focus_resource)
 | 
			
		||||
    wl_list_remove (&pointer->focus_listener.link);
 | 
			
		||||
 | 
			
		||||
  pointer->focus = NULL;
 | 
			
		||||
  pointer->focus_resource = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wl_resource *
 | 
			
		||||
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_client *client;
 | 
			
		||||
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  g_assert (surface->resource);
 | 
			
		||||
  client = wl_resource_get_client (surface->resource);
 | 
			
		||||
 | 
			
		||||
  return wl_resource_find_for_client (list, client);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
                                MetaWaylandSurface *surface,
 | 
			
		||||
                                wl_fixed_t sx, wl_fixed_t sy)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
 | 
			
		||||
  MetaWaylandKeyboard *kbd = &seat->keyboard;
 | 
			
		||||
  struct wl_resource *resource, *kr;
 | 
			
		||||
  uint32_t serial;
 | 
			
		||||
 | 
			
		||||
  resource = pointer->focus_resource;
 | 
			
		||||
  if (resource && pointer->focus != surface)
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
      wl_pointer_send_leave (resource, serial, pointer->focus->resource);
 | 
			
		||||
      wl_list_remove (&pointer->focus_listener.link);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  resource = find_resource_for_surface (&pointer->resource_list, surface);
 | 
			
		||||
  if (resource &&
 | 
			
		||||
      (pointer->focus != surface || pointer->focus_resource != resource))
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
      if (kbd)
 | 
			
		||||
        {
 | 
			
		||||
          kr = find_resource_for_surface (&kbd->resource_list, surface);
 | 
			
		||||
          if (kr)
 | 
			
		||||
            {
 | 
			
		||||
              wl_keyboard_send_modifiers (kr,
 | 
			
		||||
                                          serial,
 | 
			
		||||
                                          kbd->modifier_state.mods_depressed,
 | 
			
		||||
                                          kbd->modifier_state.mods_latched,
 | 
			
		||||
                                          kbd->modifier_state.mods_locked,
 | 
			
		||||
                                          kbd->modifier_state.group);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
 | 
			
		||||
      wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
 | 
			
		||||
      pointer->focus_serial = serial;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  pointer->focus_resource = resource;
 | 
			
		||||
  pointer->focus = surface;
 | 
			
		||||
  pointer->default_grab.focus = surface;
 | 
			
		||||
  wl_signal_emit (&pointer->focus_signal, pointer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
 | 
			
		||||
                                 MetaWaylandPointerGrab *grab)
 | 
			
		||||
{
 | 
			
		||||
  const MetaWaylandPointerGrabInterface *interface;
 | 
			
		||||
 | 
			
		||||
  pointer->grab = grab;
 | 
			
		||||
  interface = pointer->grab->interface;
 | 
			
		||||
  grab->pointer = pointer;
 | 
			
		||||
 | 
			
		||||
  if (pointer->current)
 | 
			
		||||
    interface->focus (pointer->grab, pointer->current,
 | 
			
		||||
                      pointer->current_x, pointer->current_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  const MetaWaylandPointerGrabInterface *interface;
 | 
			
		||||
 | 
			
		||||
  pointer->grab = &pointer->default_grab;
 | 
			
		||||
  interface = pointer->grab->interface;
 | 
			
		||||
  interface->focus (pointer->grab, pointer->current,
 | 
			
		||||
                    pointer->current_x, pointer->current_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
current_surface_destroy (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer =
 | 
			
		||||
    wl_container_of (listener, pointer, current_listener);
 | 
			
		||||
 | 
			
		||||
  pointer->current = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
 | 
			
		||||
                                  MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  if (pointer->current)
 | 
			
		||||
    wl_list_remove (&pointer->current_listener.link);
 | 
			
		||||
 | 
			
		||||
  pointer->current = surface;
 | 
			
		||||
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  wl_resource_add_destroy_listener (surface->resource,
 | 
			
		||||
                                    &pointer->current_listener);
 | 
			
		||||
  pointer->current_listener.notify = current_surface_destroy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
modal_focus (MetaWaylandPointerGrab *grab,
 | 
			
		||||
	     MetaWaylandSurface     *surface,
 | 
			
		||||
	     wl_fixed_t              x,
 | 
			
		||||
	     wl_fixed_t              y)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
modal_motion (MetaWaylandPointerGrab *grab,
 | 
			
		||||
	      uint32_t                time,
 | 
			
		||||
	      wl_fixed_t              x,
 | 
			
		||||
	      wl_fixed_t              y)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
modal_button (MetaWaylandPointerGrab *grab,
 | 
			
		||||
	      uint32_t                time,
 | 
			
		||||
	      uint32_t                button,
 | 
			
		||||
	      uint32_t                state)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandPointerGrabInterface modal_grab = {
 | 
			
		||||
  modal_focus,
 | 
			
		||||
  modal_motion,
 | 
			
		||||
  modal_button
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerGrab *grab;
 | 
			
		||||
 | 
			
		||||
  if (pointer->grab != &pointer->default_grab)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_set_focus (pointer, NULL,
 | 
			
		||||
				  wl_fixed_from_int (0),
 | 
			
		||||
				  wl_fixed_from_int (0));
 | 
			
		||||
 | 
			
		||||
  grab = g_slice_new0 (MetaWaylandPointerGrab);
 | 
			
		||||
  grab->interface = &modal_grab;
 | 
			
		||||
  meta_wayland_pointer_start_grab (pointer, grab);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerGrab *grab;
 | 
			
		||||
 | 
			
		||||
  grab = pointer->grab;
 | 
			
		||||
 | 
			
		||||
  g_assert (grab->interface == &modal_grab);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_end_grab (pointer);
 | 
			
		||||
  g_slice_free (MetaWaylandPointerGrab, grab);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								src/wayland/meta-wayland-pointer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/wayland/meta-wayland-pointer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library 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
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __META_WAYLAND_POINTER_H__
 | 
			
		||||
#define __META_WAYLAND_POINTER_H__
 | 
			
		||||
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-seat.h"
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_release (MetaWaylandPointer *pointer);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
                                MetaWaylandSurface *surface,
 | 
			
		||||
                                wl_fixed_t sx,
 | 
			
		||||
                                wl_fixed_t sy);
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
 | 
			
		||||
                                 MetaWaylandPointerGrab *grab);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer);
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_end_modal   (MetaWaylandPointer *pointer);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
 | 
			
		||||
                                  MetaWaylandSurface *surface);
 | 
			
		||||
 | 
			
		||||
#endif /* __META_WAYLAND_POINTER_H__ */
 | 
			
		||||
							
								
								
									
										352
									
								
								src/wayland/meta-wayland-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								src/wayland/meta-wayland-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,352 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2012 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_WAYLAND_PRIVATE_H
 | 
			
		||||
#define META_WAYLAND_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include <xkbcommon/xkbcommon.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <cairo.h>
 | 
			
		||||
 | 
			
		||||
#include "window-private.h"
 | 
			
		||||
#include "meta-tty.h"
 | 
			
		||||
#include <meta/meta-cursor-tracker.h>
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandSeat MetaWaylandSeat;
 | 
			
		||||
typedef struct _MetaWaylandPointer MetaWaylandPointer;
 | 
			
		||||
typedef struct _MetaWaylandPointerGrab MetaWaylandPointerGrab;
 | 
			
		||||
typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface;
 | 
			
		||||
typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard;
 | 
			
		||||
typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab;
 | 
			
		||||
typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface;
 | 
			
		||||
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
 | 
			
		||||
typedef struct _MetaWaylandDataSource MetaWaylandDataSource;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  struct wl_signal destroy_signal;
 | 
			
		||||
  struct wl_listener destroy_listener;
 | 
			
		||||
 | 
			
		||||
  union
 | 
			
		||||
  {
 | 
			
		||||
    struct wl_shm_buffer *shm_buffer;
 | 
			
		||||
    struct wl_buffer *legacy_buffer;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  int32_t width, height;
 | 
			
		||||
  uint32_t busy_count;
 | 
			
		||||
} MetaWaylandBuffer;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandBuffer *buffer;
 | 
			
		||||
  struct wl_listener destroy_listener;
 | 
			
		||||
} MetaWaylandBufferReference;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
} MetaWaylandRegion;
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandSurface
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
  guint32 xid;
 | 
			
		||||
  int x;
 | 
			
		||||
  int y;
 | 
			
		||||
  MetaWaylandBufferReference buffer_ref;
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
  gboolean has_shell_surface;
 | 
			
		||||
 | 
			
		||||
  /* All the pending state, that wl_surface.commit will apply. */
 | 
			
		||||
  struct
 | 
			
		||||
  {
 | 
			
		||||
    /* wl_surface.attach */
 | 
			
		||||
    gboolean newly_attached;
 | 
			
		||||
    MetaWaylandBuffer *buffer;
 | 
			
		||||
    struct wl_listener buffer_destroy_listener;
 | 
			
		||||
    int32_t sx;
 | 
			
		||||
    int32_t sy;
 | 
			
		||||
 | 
			
		||||
    /* wl_surface.damage */
 | 
			
		||||
    cairo_region_t *damage;
 | 
			
		||||
 | 
			
		||||
    /* wl_surface.frame */
 | 
			
		||||
    struct wl_list frame_callback_list;
 | 
			
		||||
  } pending;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
 | 
			
		||||
typedef struct _MetaWaylandSurface MetaWaylandSurface;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  struct wl_listener surface_destroy_listener;
 | 
			
		||||
} MetaWaylandShellSurface;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GSource source;
 | 
			
		||||
  GPollFD pfd;
 | 
			
		||||
  struct wl_display *display;
 | 
			
		||||
} WaylandEventSource;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  struct wl_list link;
 | 
			
		||||
 | 
			
		||||
  /* Pointer back to the compositor */
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
} MetaWaylandFrameCallback;
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandCompositor
 | 
			
		||||
{
 | 
			
		||||
  GHashTable *outputs;
 | 
			
		||||
 | 
			
		||||
  struct wl_display *wayland_display;
 | 
			
		||||
  struct wl_event_loop *wayland_loop;
 | 
			
		||||
  GMainLoop *init_loop;
 | 
			
		||||
  ClutterActor *stage;
 | 
			
		||||
  GSource *wayland_event_source;
 | 
			
		||||
  GList *surfaces;
 | 
			
		||||
  struct wl_list frame_callbacks;
 | 
			
		||||
 | 
			
		||||
  int xwayland_display_index;
 | 
			
		||||
  char *xwayland_lockfile;
 | 
			
		||||
  int xwayland_abstract_fd;
 | 
			
		||||
  int xwayland_unix_fd;
 | 
			
		||||
  pid_t xwayland_pid;
 | 
			
		||||
  struct wl_client *xwayland_client;
 | 
			
		||||
  struct wl_resource *xserver_resource;
 | 
			
		||||
 | 
			
		||||
  MetaTTY *tty;
 | 
			
		||||
  int drm_fd;
 | 
			
		||||
  GSocket *weston_launch;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandSeat *seat;
 | 
			
		||||
 | 
			
		||||
  /* This surface is only used to keep drag of the implicit grab when
 | 
			
		||||
     synthesizing XEvents for Mutter */
 | 
			
		||||
  MetaWaylandSurface *implicit_grab_surface;
 | 
			
		||||
  /* Button that was pressed to initiate an implicit grab. The
 | 
			
		||||
     implicit grab will only be released when this button is
 | 
			
		||||
     released */
 | 
			
		||||
  guint32 implicit_grab_button;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandPointerGrabInterface
 | 
			
		||||
{
 | 
			
		||||
  void (*focus) (MetaWaylandPointerGrab * grab,
 | 
			
		||||
                 MetaWaylandSurface * surface, wl_fixed_t x, wl_fixed_t y);
 | 
			
		||||
  void (*motion) (MetaWaylandPointerGrab * grab,
 | 
			
		||||
                  uint32_t time, wl_fixed_t x, wl_fixed_t y);
 | 
			
		||||
  void (*button) (MetaWaylandPointerGrab * grab,
 | 
			
		||||
                  uint32_t time, uint32_t button, uint32_t state);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandPointerGrab
 | 
			
		||||
{
 | 
			
		||||
  const MetaWaylandPointerGrabInterface *interface;
 | 
			
		||||
  MetaWaylandPointer *pointer;
 | 
			
		||||
  MetaWaylandSurface *focus;
 | 
			
		||||
  wl_fixed_t x, y;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandPointer
 | 
			
		||||
{
 | 
			
		||||
  struct wl_list resource_list;
 | 
			
		||||
  MetaWaylandSurface *focus;
 | 
			
		||||
  struct wl_resource *focus_resource;
 | 
			
		||||
  struct wl_listener focus_listener;
 | 
			
		||||
  guint32 focus_serial;
 | 
			
		||||
  struct wl_signal focus_signal;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandPointerGrab *grab;
 | 
			
		||||
  MetaWaylandPointerGrab default_grab;
 | 
			
		||||
  wl_fixed_t grab_x, grab_y;
 | 
			
		||||
  guint32 grab_button;
 | 
			
		||||
  guint32 grab_serial;
 | 
			
		||||
  guint32 grab_time;
 | 
			
		||||
 | 
			
		||||
  wl_fixed_t x, y;
 | 
			
		||||
  MetaWaylandSurface *current;
 | 
			
		||||
  struct wl_listener current_listener;
 | 
			
		||||
  wl_fixed_t current_x, current_y;
 | 
			
		||||
 | 
			
		||||
  guint32 button_count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandKeyboardGrabInterface
 | 
			
		||||
{
 | 
			
		||||
  void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
 | 
			
		||||
               uint32_t key, uint32_t state);
 | 
			
		||||
  void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
 | 
			
		||||
                     uint32_t mods_depressed, uint32_t mods_latched,
 | 
			
		||||
                     uint32_t mods_locked, uint32_t group);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandKeyboardGrab
 | 
			
		||||
{
 | 
			
		||||
  const MetaWaylandKeyboardGrabInterface *interface;
 | 
			
		||||
  MetaWaylandKeyboard *keyboard;
 | 
			
		||||
  MetaWaylandSurface *focus;
 | 
			
		||||
  uint32_t key;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  struct xkb_keymap *keymap;
 | 
			
		||||
  int keymap_fd;
 | 
			
		||||
  size_t keymap_size;
 | 
			
		||||
  char *keymap_area;
 | 
			
		||||
  xkb_mod_index_t shift_mod;
 | 
			
		||||
  xkb_mod_index_t caps_mod;
 | 
			
		||||
  xkb_mod_index_t ctrl_mod;
 | 
			
		||||
  xkb_mod_index_t alt_mod;
 | 
			
		||||
  xkb_mod_index_t mod2_mod;
 | 
			
		||||
  xkb_mod_index_t mod3_mod;
 | 
			
		||||
  xkb_mod_index_t super_mod;
 | 
			
		||||
  xkb_mod_index_t mod5_mod;
 | 
			
		||||
} MetaWaylandXkbInfo;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  uint32_t mods_depressed;
 | 
			
		||||
  uint32_t mods_latched;
 | 
			
		||||
  uint32_t mods_locked;
 | 
			
		||||
  uint32_t group;
 | 
			
		||||
} MetaWaylandXkbState;
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandKeyboard
 | 
			
		||||
{
 | 
			
		||||
  struct wl_list resource_list;
 | 
			
		||||
  MetaWaylandSurface *focus;
 | 
			
		||||
  struct wl_resource *focus_resource;
 | 
			
		||||
  struct wl_listener focus_listener;
 | 
			
		||||
  uint32_t focus_serial;
 | 
			
		||||
  struct wl_signal focus_signal;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandKeyboardGrab *grab;
 | 
			
		||||
  MetaWaylandKeyboardGrab default_grab;
 | 
			
		||||
  uint32_t grab_key;
 | 
			
		||||
  uint32_t grab_serial;
 | 
			
		||||
  uint32_t grab_time;
 | 
			
		||||
 | 
			
		||||
  struct wl_array keys;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandXkbState modifier_state;
 | 
			
		||||
 | 
			
		||||
  struct wl_display *display;
 | 
			
		||||
 | 
			
		||||
  struct xkb_context *xkb_context;
 | 
			
		||||
  struct xkb_state *xkb_state;
 | 
			
		||||
  gboolean is_evdev;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandXkbInfo xkb_info;
 | 
			
		||||
  struct xkb_rule_names xkb_names;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandKeyboardGrab input_method_grab;
 | 
			
		||||
  struct wl_resource *input_method_resource;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandDataOffer
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  MetaWaylandDataSource *source;
 | 
			
		||||
  struct wl_listener source_destroy_listener;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandDataSource
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  struct wl_array mime_types;
 | 
			
		||||
 | 
			
		||||
  void (*accept) (MetaWaylandDataSource * source,
 | 
			
		||||
                  uint32_t serial, const char *mime_type);
 | 
			
		||||
  void (*send) (MetaWaylandDataSource * source,
 | 
			
		||||
                const char *mime_type, int32_t fd);
 | 
			
		||||
  void (*cancel) (MetaWaylandDataSource * source);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandSeat
 | 
			
		||||
{
 | 
			
		||||
  struct wl_list base_resource_list;
 | 
			
		||||
  struct wl_signal destroy_signal;
 | 
			
		||||
 | 
			
		||||
  uint32_t selection_serial;
 | 
			
		||||
  MetaWaylandDataSource *selection_data_source;
 | 
			
		||||
  struct wl_listener selection_data_source_listener;
 | 
			
		||||
  struct wl_signal selection_signal;
 | 
			
		||||
 | 
			
		||||
  struct wl_list drag_resource_list;
 | 
			
		||||
  struct wl_client *drag_client;
 | 
			
		||||
  MetaWaylandDataSource *drag_data_source;
 | 
			
		||||
  struct wl_listener drag_data_source_listener;
 | 
			
		||||
  MetaWaylandSurface *drag_focus;
 | 
			
		||||
  struct wl_resource *drag_focus_resource;
 | 
			
		||||
  struct wl_listener drag_focus_listener;
 | 
			
		||||
  MetaWaylandPointerGrab drag_grab;
 | 
			
		||||
  MetaWaylandSurface *drag_surface;
 | 
			
		||||
  struct wl_listener drag_icon_listener;
 | 
			
		||||
  struct wl_signal drag_icon_signal;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandPointer pointer;
 | 
			
		||||
  MetaWaylandKeyboard keyboard;
 | 
			
		||||
 | 
			
		||||
  struct wl_display *display;
 | 
			
		||||
 | 
			
		||||
  MetaCursorTracker *cursor_tracker;
 | 
			
		||||
  MetaWaylandSurface *sprite;
 | 
			
		||||
  int hotspot_x, hotspot_y;
 | 
			
		||||
  struct wl_listener sprite_destroy_listener;
 | 
			
		||||
 | 
			
		||||
  ClutterActor *current_stage;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void                    meta_wayland_init                       (void);
 | 
			
		||||
void                    meta_wayland_finalize                   (void);
 | 
			
		||||
 | 
			
		||||
/* We maintain a singleton MetaWaylandCompositor which can be got at via this
 | 
			
		||||
 * API after meta_wayland_init() has been called. */
 | 
			
		||||
MetaWaylandCompositor  *meta_wayland_compositor_get_default     (void);
 | 
			
		||||
 | 
			
		||||
void                    meta_wayland_compositor_repick          (MetaWaylandCompositor *compositor);
 | 
			
		||||
 | 
			
		||||
void                    meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
 | 
			
		||||
                                                                 MetaWindow            *window);
 | 
			
		||||
 | 
			
		||||
MetaTTY                *meta_wayland_compositor_get_tty         (MetaWaylandCompositor *compositor);
 | 
			
		||||
gboolean                meta_wayland_compositor_is_native       (MetaWaylandCompositor *compositor);
 | 
			
		||||
 | 
			
		||||
void                    meta_wayland_surface_free               (MetaWaylandSurface    *surface);
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										552
									
								
								src/wayland/meta-wayland-seat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										552
									
								
								src/wayland/meta-wayland-seat.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,552 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <cogl/cogl-wayland-server.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <clutter/wayland/clutter-wayland-compositor.h>
 | 
			
		||||
#include <clutter/wayland/clutter-wayland-surface.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "meta-wayland-seat.h"
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-wayland-keyboard.h"
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
#include "meta-wayland-data-device.h"
 | 
			
		||||
#include "meta-window-actor-private.h"
 | 
			
		||||
#include "meta/meta-shaped-texture.h"
 | 
			
		||||
#include "meta-wayland-stage.h"
 | 
			
		||||
#include "meta-cursor-tracker-private.h"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
unbind_resource (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_list_remove (wl_resource_get_link (resource));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
transform_stage_point_fixed (MetaWaylandSurface *surface,
 | 
			
		||||
                             wl_fixed_t x,
 | 
			
		||||
                             wl_fixed_t y,
 | 
			
		||||
                             wl_fixed_t *sx,
 | 
			
		||||
                             wl_fixed_t *sy)
 | 
			
		||||
{
 | 
			
		||||
  float xf = 0.0f, yf = 0.0f;
 | 
			
		||||
 | 
			
		||||
  if (surface->window)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterActor *actor =
 | 
			
		||||
        CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
 | 
			
		||||
 | 
			
		||||
      if (actor)
 | 
			
		||||
        clutter_actor_transform_stage_point (actor,
 | 
			
		||||
                                             wl_fixed_to_double (x),
 | 
			
		||||
                                             wl_fixed_to_double (y),
 | 
			
		||||
                                             &xf, &yf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  *sx = wl_fixed_from_double (xf);
 | 
			
		||||
  *sy = wl_fixed_from_double (yf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_unmap_sprite (MetaWaylandSeat *seat)
 | 
			
		||||
{
 | 
			
		||||
  if (seat->cursor_tracker)
 | 
			
		||||
    {
 | 
			
		||||
      meta_cursor_tracker_set_sprite (seat->cursor_tracker,
 | 
			
		||||
				      NULL, 0, 0);
 | 
			
		||||
 | 
			
		||||
      if (seat->current_stage)
 | 
			
		||||
	meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
 | 
			
		||||
					  CLUTTER_ACTOR (seat->current_stage));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (seat->sprite)
 | 
			
		||||
    {
 | 
			
		||||
      wl_list_remove (&seat->sprite_destroy_listener.link);
 | 
			
		||||
      seat->sprite = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
 | 
			
		||||
{
 | 
			
		||||
  ClutterBackend *backend;
 | 
			
		||||
  CoglContext *context;
 | 
			
		||||
  struct wl_resource *buffer;
 | 
			
		||||
  CoglTexture2D *texture;
 | 
			
		||||
 | 
			
		||||
  if (seat->cursor_tracker == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  backend = clutter_get_default_backend ();
 | 
			
		||||
  context = clutter_backend_get_cogl_context (backend);
 | 
			
		||||
  buffer = seat->sprite->buffer_ref.buffer->resource;
 | 
			
		||||
  texture = cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL);
 | 
			
		||||
 | 
			
		||||
  meta_cursor_tracker_set_sprite (seat->cursor_tracker,
 | 
			
		||||
				  texture,
 | 
			
		||||
				  seat->hotspot_x,
 | 
			
		||||
				  seat->hotspot_y);
 | 
			
		||||
 | 
			
		||||
  if (seat->current_stage)
 | 
			
		||||
    meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
 | 
			
		||||
				      CLUTTER_ACTOR (seat->current_stage));
 | 
			
		||||
 | 
			
		||||
  cogl_object_unref (texture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_set_cursor (struct wl_client *client,
 | 
			
		||||
                    struct wl_resource *resource,
 | 
			
		||||
                    uint32_t serial,
 | 
			
		||||
                    struct wl_resource *surface_resource,
 | 
			
		||||
                    int32_t x, int32_t y)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
 | 
			
		||||
  surface = (surface_resource ?
 | 
			
		||||
             wl_resource_get_user_data (surface_resource) :
 | 
			
		||||
             NULL);
 | 
			
		||||
 | 
			
		||||
  if (seat->pointer.focus == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
  if (wl_resource_get_client (seat->pointer.focus->resource) != client)
 | 
			
		||||
    return;
 | 
			
		||||
  if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  seat->hotspot_x = x;
 | 
			
		||||
  seat->hotspot_y = y;
 | 
			
		||||
 | 
			
		||||
  if (seat->sprite != surface)
 | 
			
		||||
    {
 | 
			
		||||
      pointer_unmap_sprite (seat);
 | 
			
		||||
 | 
			
		||||
      if (!surface)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
      wl_resource_add_destroy_listener (surface->resource,
 | 
			
		||||
                                        &seat->sprite_destroy_listener);
 | 
			
		||||
 | 
			
		||||
      seat->sprite = surface;
 | 
			
		||||
 | 
			
		||||
      if (seat->sprite->buffer_ref.buffer)
 | 
			
		||||
        meta_wayland_seat_update_sprite (seat);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_pointer_interface
 | 
			
		||||
pointer_interface =
 | 
			
		||||
  {
 | 
			
		||||
    pointer_set_cursor
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
seat_get_pointer (struct wl_client *client,
 | 
			
		||||
                  struct wl_resource *resource,
 | 
			
		||||
                  uint32_t id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
 | 
			
		||||
  struct wl_resource *cr;
 | 
			
		||||
 | 
			
		||||
  cr = wl_client_add_object (client, &wl_pointer_interface,
 | 
			
		||||
                             &pointer_interface, id, seat);
 | 
			
		||||
  wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr));
 | 
			
		||||
  wl_resource_set_destructor (cr, unbind_resource);
 | 
			
		||||
 | 
			
		||||
  if (seat->pointer.focus &&
 | 
			
		||||
      wl_resource_get_client (seat->pointer.focus->resource) == client)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandSurface *surface;
 | 
			
		||||
      wl_fixed_t sx, sy;
 | 
			
		||||
 | 
			
		||||
      surface = (MetaWaylandSurface *) seat->pointer.focus;
 | 
			
		||||
      transform_stage_point_fixed (surface,
 | 
			
		||||
                                   seat->pointer.x,
 | 
			
		||||
                                   seat->pointer.y,
 | 
			
		||||
                                   &sx, &sy);
 | 
			
		||||
      meta_wayland_pointer_set_focus (&seat->pointer,
 | 
			
		||||
                                  seat->pointer.focus,
 | 
			
		||||
                                  sx, sy);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
seat_get_keyboard (struct wl_client *client,
 | 
			
		||||
                   struct wl_resource *resource,
 | 
			
		||||
                   uint32_t id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
 | 
			
		||||
  struct wl_resource *cr;
 | 
			
		||||
 | 
			
		||||
  cr = wl_client_add_object (client, &wl_keyboard_interface, NULL, id, seat);
 | 
			
		||||
  wl_list_insert (&seat->keyboard.resource_list, wl_resource_get_link (cr));
 | 
			
		||||
  wl_resource_set_destructor (cr, unbind_resource);
 | 
			
		||||
 | 
			
		||||
  wl_keyboard_send_keymap (cr,
 | 
			
		||||
                           WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
 | 
			
		||||
                           seat->keyboard.xkb_info.keymap_fd,
 | 
			
		||||
                           seat->keyboard.xkb_info.keymap_size);
 | 
			
		||||
 | 
			
		||||
  if (seat->keyboard.focus &&
 | 
			
		||||
      wl_resource_get_client (seat->keyboard.focus->resource) == client)
 | 
			
		||||
    {
 | 
			
		||||
      meta_wayland_keyboard_set_focus (&seat->keyboard,
 | 
			
		||||
                                   seat->keyboard.focus);
 | 
			
		||||
      meta_wayland_data_device_set_keyboard_focus (seat);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
seat_get_touch (struct wl_client *client,
 | 
			
		||||
                struct wl_resource *resource,
 | 
			
		||||
                uint32_t id)
 | 
			
		||||
{
 | 
			
		||||
  /* Touch not supported */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_seat_interface
 | 
			
		||||
seat_interface =
 | 
			
		||||
  {
 | 
			
		||||
    seat_get_pointer,
 | 
			
		||||
    seat_get_keyboard,
 | 
			
		||||
    seat_get_touch
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bind_seat (struct wl_client *client,
 | 
			
		||||
           void *data,
 | 
			
		||||
           guint32 version,
 | 
			
		||||
           guint32 id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = data;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  resource = wl_client_add_object (client,
 | 
			
		||||
                                   &wl_seat_interface,
 | 
			
		||||
                                   &seat_interface,
 | 
			
		||||
                                   id,
 | 
			
		||||
                                   data);
 | 
			
		||||
  wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource));
 | 
			
		||||
  wl_resource_set_destructor (resource, unbind_resource);
 | 
			
		||||
 | 
			
		||||
  wl_seat_send_capabilities (resource,
 | 
			
		||||
                             WL_SEAT_CAPABILITY_POINTER |
 | 
			
		||||
                             WL_SEAT_CAPABILITY_KEYBOARD);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat =
 | 
			
		||||
    wl_container_of (listener, seat, sprite_destroy_listener);
 | 
			
		||||
 | 
			
		||||
  pointer_unmap_sprite (seat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandSeat *
 | 
			
		||||
meta_wayland_seat_new (struct wl_display *display,
 | 
			
		||||
		       gboolean           is_native)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
 | 
			
		||||
 | 
			
		||||
  wl_signal_init (&seat->destroy_signal);
 | 
			
		||||
 | 
			
		||||
  seat->selection_data_source = NULL;
 | 
			
		||||
  wl_list_init (&seat->base_resource_list);
 | 
			
		||||
  wl_signal_init (&seat->selection_signal);
 | 
			
		||||
  wl_list_init (&seat->drag_resource_list);
 | 
			
		||||
  wl_signal_init (&seat->drag_icon_signal);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_init (&seat->pointer);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
 | 
			
		||||
 | 
			
		||||
  seat->display = display;
 | 
			
		||||
 | 
			
		||||
  seat->current_stage = 0;
 | 
			
		||||
 | 
			
		||||
  seat->sprite = NULL;
 | 
			
		||||
  seat->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
 | 
			
		||||
  seat->hotspot_x = 16;
 | 
			
		||||
  seat->hotspot_y = 16;
 | 
			
		||||
 | 
			
		||||
  wl_display_add_global (display, &wl_seat_interface, seat, bind_seat);
 | 
			
		||||
 | 
			
		||||
  return seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
notify_motion (MetaWaylandSeat *seat,
 | 
			
		||||
               const ClutterEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = &seat->pointer;
 | 
			
		||||
  float x, y;
 | 
			
		||||
 | 
			
		||||
  clutter_event_get_coords (event, &x, &y);
 | 
			
		||||
  pointer->x = wl_fixed_from_double (x);
 | 
			
		||||
  pointer->y = wl_fixed_from_double (y);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_seat_repick (seat,
 | 
			
		||||
                        clutter_event_get_time (event),
 | 
			
		||||
                        clutter_event_get_source (event));
 | 
			
		||||
 | 
			
		||||
  pointer->grab->interface->motion (pointer->grab,
 | 
			
		||||
                                    clutter_event_get_time (event),
 | 
			
		||||
                                    pointer->grab->x,
 | 
			
		||||
                                    pointer->grab->y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_motion_event (MetaWaylandSeat *seat,
 | 
			
		||||
                     const ClutterMotionEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  notify_motion (seat, (const ClutterEvent *) event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_button_event (MetaWaylandSeat *seat,
 | 
			
		||||
                     const ClutterButtonEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = &seat->pointer;
 | 
			
		||||
  gboolean state = event->type == CLUTTER_BUTTON_PRESS;
 | 
			
		||||
  uint32_t button;
 | 
			
		||||
 | 
			
		||||
  notify_motion (seat, (const ClutterEvent *) event);
 | 
			
		||||
 | 
			
		||||
  switch (event->button)
 | 
			
		||||
    {
 | 
			
		||||
      /* The evdev input right and middle button numbers are swapped
 | 
			
		||||
         relative to how Clutter numbers them */
 | 
			
		||||
    case 2:
 | 
			
		||||
      button = BTN_MIDDLE;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 3:
 | 
			
		||||
      button = BTN_RIGHT;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      button = event->button + BTN_LEFT - 1;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (state)
 | 
			
		||||
    {
 | 
			
		||||
      if (pointer->button_count == 0)
 | 
			
		||||
        {
 | 
			
		||||
          MetaWaylandSurface *surface = pointer->current;
 | 
			
		||||
 | 
			
		||||
          pointer->grab_button = button;
 | 
			
		||||
          pointer->grab_time = event->time;
 | 
			
		||||
          pointer->grab_x = pointer->x;
 | 
			
		||||
          pointer->grab_y = pointer->y;
 | 
			
		||||
 | 
			
		||||
          if (button == BTN_LEFT &&
 | 
			
		||||
              surface &&
 | 
			
		||||
              surface->window &&
 | 
			
		||||
              surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
 | 
			
		||||
            {
 | 
			
		||||
              meta_window_raise (surface->window);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      pointer->button_count++;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    pointer->button_count--;
 | 
			
		||||
 | 
			
		||||
  pointer->grab->interface->button (pointer->grab, event->time, button, state);
 | 
			
		||||
 | 
			
		||||
  if (pointer->button_count == 1)
 | 
			
		||||
    pointer->grab_serial = wl_display_get_serial (seat->display);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_scroll_event (MetaWaylandSeat *seat,
 | 
			
		||||
                     const ClutterScrollEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  enum wl_pointer_axis axis;
 | 
			
		||||
  wl_fixed_t value;
 | 
			
		||||
 | 
			
		||||
  notify_motion (seat, (const ClutterEvent *) event);
 | 
			
		||||
 | 
			
		||||
  switch (event->direction)
 | 
			
		||||
    {
 | 
			
		||||
    case CLUTTER_SCROLL_UP:
 | 
			
		||||
      axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
 | 
			
		||||
      value = -DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_DOWN:
 | 
			
		||||
      axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
 | 
			
		||||
      value = DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_LEFT:
 | 
			
		||||
      axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
 | 
			
		||||
      value = -DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_RIGHT:
 | 
			
		||||
      axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
 | 
			
		||||
      value = DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (seat->pointer.focus_resource)
 | 
			
		||||
    wl_pointer_send_axis (seat->pointer.focus_resource,
 | 
			
		||||
                          event->time,
 | 
			
		||||
                          axis,
 | 
			
		||||
                          value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
 | 
			
		||||
                                const ClutterEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  switch (event->type)
 | 
			
		||||
    {
 | 
			
		||||
    case CLUTTER_MOTION:
 | 
			
		||||
      handle_motion_event (seat,
 | 
			
		||||
                           (const ClutterMotionEvent *) event);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_BUTTON_PRESS:
 | 
			
		||||
    case CLUTTER_BUTTON_RELEASE:
 | 
			
		||||
      handle_button_event (seat,
 | 
			
		||||
                           (const ClutterButtonEvent *) event);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_KEY_PRESS:
 | 
			
		||||
    case CLUTTER_KEY_RELEASE:
 | 
			
		||||
      meta_wayland_keyboard_handle_event (&seat->keyboard,
 | 
			
		||||
                                          (const ClutterKeyEvent *) event);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL:
 | 
			
		||||
      handle_scroll_event (seat, (const ClutterScrollEvent *) event);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_pointer_position_for_actor (MetaWaylandPointer *pointer,
 | 
			
		||||
                                   ClutterActor *actor)
 | 
			
		||||
{
 | 
			
		||||
  float ax, ay;
 | 
			
		||||
 | 
			
		||||
  clutter_actor_transform_stage_point (actor,
 | 
			
		||||
                                       wl_fixed_to_double (pointer->x),
 | 
			
		||||
                                       wl_fixed_to_double (pointer->y),
 | 
			
		||||
                                       &ax, &ay);
 | 
			
		||||
  pointer->current_x = wl_fixed_from_double (ax);
 | 
			
		||||
  pointer->current_y = wl_fixed_from_double (ay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The actor argument can be NULL in which case a Clutter pick will be
 | 
			
		||||
   performed to determine the right actor. An actor should only be
 | 
			
		||||
   passed if the repick is being performed due to an event in which
 | 
			
		||||
   case Clutter will have already performed a pick so we can avoid
 | 
			
		||||
   redundantly doing another one */
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_repick (MetaWaylandSeat *seat,
 | 
			
		||||
                          uint32_t time,
 | 
			
		||||
                          ClutterActor *actor)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = &seat->pointer;
 | 
			
		||||
  MetaWaylandSurface *surface = NULL;
 | 
			
		||||
 | 
			
		||||
  if (actor == NULL && seat->current_stage)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterStage *stage = CLUTTER_STAGE (seat->current_stage);
 | 
			
		||||
      actor = clutter_stage_get_actor_at_pos (stage,
 | 
			
		||||
                                              CLUTTER_PICK_REACTIVE,
 | 
			
		||||
                                              wl_fixed_to_double (pointer->x),
 | 
			
		||||
                                              wl_fixed_to_double (pointer->y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (actor)
 | 
			
		||||
    seat->current_stage = clutter_actor_get_stage (actor);
 | 
			
		||||
  else
 | 
			
		||||
    seat->current_stage = NULL;
 | 
			
		||||
 | 
			
		||||
  if (META_IS_WINDOW_ACTOR (actor))
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindow *window =
 | 
			
		||||
        meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
 | 
			
		||||
 | 
			
		||||
      update_pointer_position_for_actor (pointer, actor);
 | 
			
		||||
 | 
			
		||||
      surface = window->surface;
 | 
			
		||||
    }
 | 
			
		||||
  else if (META_IS_SHAPED_TEXTURE (actor))
 | 
			
		||||
    {
 | 
			
		||||
      MetaShapedTexture *shaped_texture = META_SHAPED_TEXTURE (actor);
 | 
			
		||||
 | 
			
		||||
      update_pointer_position_for_actor (pointer, actor);
 | 
			
		||||
 | 
			
		||||
      surface = meta_shaped_texture_get_wayland_surface (shaped_texture);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  pointer->current = surface;
 | 
			
		||||
  if (surface != pointer->focus)
 | 
			
		||||
    {
 | 
			
		||||
      const MetaWaylandPointerGrabInterface *interface =
 | 
			
		||||
        pointer->grab->interface;
 | 
			
		||||
      interface->focus (pointer->grab,
 | 
			
		||||
                        surface,
 | 
			
		||||
                        pointer->current_x, pointer->current_y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (pointer->grab->focus)
 | 
			
		||||
    transform_stage_point_fixed (pointer->grab->focus,
 | 
			
		||||
                                 pointer->x,
 | 
			
		||||
                                 pointer->y,
 | 
			
		||||
                                 &pointer->grab->x,
 | 
			
		||||
                                 &pointer->grab->y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_free (MetaWaylandSeat *seat)
 | 
			
		||||
{
 | 
			
		||||
  pointer_unmap_sprite (seat);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_release (&seat->pointer);
 | 
			
		||||
  meta_wayland_keyboard_release (&seat->keyboard);
 | 
			
		||||
 | 
			
		||||
  wl_signal_emit (&seat->destroy_signal, seat);
 | 
			
		||||
 | 
			
		||||
  g_slice_free (MetaWaylandSeat, seat);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/wayland/meta-wayland-seat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/wayland/meta-wayland-seat.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2012 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __META_WAYLAND_SEAT_H__
 | 
			
		||||
#define __META_WAYLAND_SEAT_H__
 | 
			
		||||
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include <xkbcommon/xkbcommon.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
 | 
			
		||||
MetaWaylandSeat *
 | 
			
		||||
meta_wayland_seat_new (struct wl_display *display,
 | 
			
		||||
		       gboolean           is_native);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
 | 
			
		||||
                                const ClutterEvent *event);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_repick (MetaWaylandSeat *seat,
 | 
			
		||||
                          uint32_t time,
 | 
			
		||||
                          ClutterActor *actor);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_seat_free (MetaWaylandSeat *seat);
 | 
			
		||||
 | 
			
		||||
#endif /* __META_WAYLAND_SEAT_H__ */
 | 
			
		||||
							
								
								
									
										68
									
								
								src/wayland/meta-wayland-stage.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/wayland/meta-wayland-stage.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2012 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <gdk-pixbuf/gdk-pixbuf.h>
 | 
			
		||||
#include <cogl/cogl-wayland-server.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-stage.h"
 | 
			
		||||
#include "meta/meta-window-actor.h"
 | 
			
		||||
#include "meta/meta-shaped-texture.h"
 | 
			
		||||
#include "meta-cursor-tracker-private.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_stage_paint (ClutterActor *actor)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor;
 | 
			
		||||
 | 
			
		||||
  CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->paint (actor);
 | 
			
		||||
 | 
			
		||||
  compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  if (compositor->seat->cursor_tracker)
 | 
			
		||||
    meta_cursor_tracker_paint (compositor->seat->cursor_tracker);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_stage_class_init (MetaWaylandStageClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  ClutterActorClass *actor_class = (ClutterActorClass *) klass;
 | 
			
		||||
 | 
			
		||||
  actor_class->paint = meta_wayland_stage_paint;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_stage_init (MetaWaylandStage *self)
 | 
			
		||||
{
 | 
			
		||||
  clutter_stage_set_user_resizable (CLUTTER_STAGE (self), FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ClutterActor *
 | 
			
		||||
meta_wayland_stage_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (META_WAYLAND_TYPE_STAGE,
 | 
			
		||||
                       "cursor-visible", FALSE,
 | 
			
		||||
                       NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										70
									
								
								src/wayland/meta-wayland-stage.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/wayland/meta-wayland-stage.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2012 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_WAYLAND_STAGE_H
 | 
			
		||||
#define META_WAYLAND_STAGE_H
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
#include "window-private.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_WAYLAND_TYPE_STAGE                                         \
 | 
			
		||||
  (meta_wayland_stage_get_type())
 | 
			
		||||
#define META_WAYLAND_STAGE(obj)                                         \
 | 
			
		||||
  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
 | 
			
		||||
                               META_WAYLAND_TYPE_STAGE,                 \
 | 
			
		||||
                               MetaWaylandStage))
 | 
			
		||||
#define META_WAYLAND_STAGE_CLASS(klass)                                 \
 | 
			
		||||
  (G_TYPE_CHECK_CLASS_CAST ((klass),                                    \
 | 
			
		||||
                            META_WAYLAND_TYPE_STAGE,                    \
 | 
			
		||||
                            MetaWaylandStageClass))
 | 
			
		||||
#define META_WAYLAND_IS_STAGE(obj)                                      \
 | 
			
		||||
  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
 | 
			
		||||
                               META_WAYLAND_TYPE_STAGE))
 | 
			
		||||
#define META_WAYLAND_IS_STAGE_CLASS(klass)                              \
 | 
			
		||||
  (G_TYPE_CHECK_CLASS_TYPE ((klass),                                    \
 | 
			
		||||
                            META_WAYLAND_TYPE_STAGE))
 | 
			
		||||
#define META_WAYLAND_STAGE_GET_CLASS(obj)                               \
 | 
			
		||||
  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
 | 
			
		||||
                              META_WAYLAND_STAGE,                       \
 | 
			
		||||
                              MetaWaylandStageClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandStage      MetaWaylandStage;
 | 
			
		||||
typedef struct _MetaWaylandStageClass MetaWaylandStageClass;
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandStageClass
 | 
			
		||||
{
 | 
			
		||||
  ClutterStageClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandStage
 | 
			
		||||
{
 | 
			
		||||
  ClutterStage parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType             meta_wayland_stage_get_type                (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
ClutterActor     *meta_wayland_stage_new                     (void);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_STAGE_H */
 | 
			
		||||
							
								
								
									
										1875
									
								
								src/wayland/meta-wayland.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1875
									
								
								src/wayland/meta-wayland.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										203
									
								
								src/wayland/meta-weston-launch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/wayland/meta-weston-launch.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <gio/gunixfdmessage.h>
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
 | 
			
		||||
#include <drm.h>
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-weston-launch.h"
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
send_message_to_wl (GSocket                *weston_launch,
 | 
			
		||||
		    void                   *message,
 | 
			
		||||
		    gsize                   size,
 | 
			
		||||
		    GSocketControlMessage  *out_cmsg,
 | 
			
		||||
		    GSocketControlMessage **in_cmsg,
 | 
			
		||||
		    GError                **error)
 | 
			
		||||
{
 | 
			
		||||
  int ok;
 | 
			
		||||
  GInputVector in_iov = { &ok, sizeof (int) };
 | 
			
		||||
  GOutputVector out_iov = { message, size };
 | 
			
		||||
  GSocketControlMessage *out_all_cmsg[2];
 | 
			
		||||
  GSocketControlMessage **in_all_cmsg;
 | 
			
		||||
  int flags = 0;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  out_all_cmsg[0] = out_cmsg;
 | 
			
		||||
  out_all_cmsg[1] = NULL;
 | 
			
		||||
  if (g_socket_send_message (weston_launch, NULL,
 | 
			
		||||
			     &out_iov, 1,
 | 
			
		||||
			     out_all_cmsg, -1,
 | 
			
		||||
			     flags, NULL, error) != (gssize)size)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (g_socket_receive_message (weston_launch, NULL,
 | 
			
		||||
				&in_iov, 1,
 | 
			
		||||
				&in_all_cmsg, NULL,
 | 
			
		||||
				&flags, NULL, error) != sizeof (int))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (ok != 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (ok == -1)
 | 
			
		||||
	g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 | 
			
		||||
		     "Got failure from weston-launch");
 | 
			
		||||
      else
 | 
			
		||||
	g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ok),
 | 
			
		||||
		     "Got failure from weston-launch: %s", strerror (-ok));
 | 
			
		||||
 | 
			
		||||
      for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
 | 
			
		||||
	g_object_unref (in_all_cmsg[i]);
 | 
			
		||||
      g_free (in_all_cmsg);
 | 
			
		||||
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (in_all_cmsg && in_all_cmsg[0])
 | 
			
		||||
    {
 | 
			
		||||
      for (i = 1; in_all_cmsg[i]; i++)
 | 
			
		||||
	g_object_unref (in_all_cmsg[i]);
 | 
			
		||||
      *in_cmsg = in_all_cmsg[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (in_all_cmsg);
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}	    
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_weston_launch_set_master (GSocket   *weston_launch,
 | 
			
		||||
			       int        drm_fd,
 | 
			
		||||
			       gboolean   master,
 | 
			
		||||
			       GError   **error)
 | 
			
		||||
{
 | 
			
		||||
  if (weston_launch)
 | 
			
		||||
    {
 | 
			
		||||
      struct weston_launcher_set_master message;
 | 
			
		||||
      GSocketControlMessage *cmsg;
 | 
			
		||||
      gboolean ok;
 | 
			
		||||
 | 
			
		||||
      message.header.opcode = WESTON_LAUNCHER_DRM_SET_MASTER;
 | 
			
		||||
      message.set_master = master;
 | 
			
		||||
 | 
			
		||||
      cmsg = g_unix_fd_message_new ();
 | 
			
		||||
      if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
 | 
			
		||||
				       drm_fd, error) == FALSE)
 | 
			
		||||
	{
 | 
			
		||||
	  g_object_unref (cmsg);
 | 
			
		||||
	  return FALSE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      ok = send_message_to_wl (weston_launch, &message, sizeof message, cmsg, NULL, error);
 | 
			
		||||
 | 
			
		||||
      g_object_unref (cmsg);
 | 
			
		||||
      return ok;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      int ret;
 | 
			
		||||
 | 
			
		||||
      if (master)
 | 
			
		||||
	ret = drmSetMaster (drm_fd);
 | 
			
		||||
      else
 | 
			
		||||
	ret = drmDropMaster (drm_fd);
 | 
			
		||||
 | 
			
		||||
      if (ret < 0)
 | 
			
		||||
	{
 | 
			
		||||
	  g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
 | 
			
		||||
		       "Failed to set DRM master directly: %s", strerror (-ret));
 | 
			
		||||
	  return FALSE;
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
meta_weston_launch_open_input_device (GSocket    *weston_launch,
 | 
			
		||||
				      const char *name,
 | 
			
		||||
				      int         flags,
 | 
			
		||||
				      GError    **error)
 | 
			
		||||
{
 | 
			
		||||
  if (weston_launch)
 | 
			
		||||
    {
 | 
			
		||||
      struct weston_launcher_open *message;
 | 
			
		||||
      GSocketControlMessage *cmsg;
 | 
			
		||||
      gboolean ok;
 | 
			
		||||
      gsize size;
 | 
			
		||||
      int *fds, n_fd;
 | 
			
		||||
      int ret;
 | 
			
		||||
 | 
			
		||||
      size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
 | 
			
		||||
      message = g_malloc (size);
 | 
			
		||||
      message->header.opcode = WESTON_LAUNCHER_OPEN;
 | 
			
		||||
      message->flags = flags;
 | 
			
		||||
      strcpy (message->path, name);
 | 
			
		||||
      message->path[strlen(name)] = 0;
 | 
			
		||||
 | 
			
		||||
      ok = send_message_to_wl (weston_launch, message, size,
 | 
			
		||||
			       NULL, &cmsg, error);
 | 
			
		||||
 | 
			
		||||
      if (ok)
 | 
			
		||||
	{
 | 
			
		||||
	  g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
 | 
			
		||||
 | 
			
		||||
	  fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
 | 
			
		||||
	  g_assert (n_fd == 1);
 | 
			
		||||
 | 
			
		||||
	  ret = fds[0];
 | 
			
		||||
	  g_free (fds);
 | 
			
		||||
	  g_object_unref (cmsg);
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	ret = -1;
 | 
			
		||||
 | 
			
		||||
      g_free (message);
 | 
			
		||||
      return ret;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      int ret;
 | 
			
		||||
 | 
			
		||||
      ret = open (name, flags, 0);
 | 
			
		||||
 | 
			
		||||
      if (ret < 0)
 | 
			
		||||
	g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
 | 
			
		||||
		     "Failed to open input device directly: %s", strerror (errno));
 | 
			
		||||
 | 
			
		||||
      return ret;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								src/wayland/meta-weston-launch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/wayland/meta-weston-launch.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_WESTON_LAUNCH_H
 | 
			
		||||
#define META_WESTON_LAUNCH_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
/* Keep this in sync with weston-launch */
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_opcode {
 | 
			
		||||
	WESTON_LAUNCHER_OPEN,
 | 
			
		||||
	WESTON_LAUNCHER_DRM_SET_MASTER
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_message {
 | 
			
		||||
	int opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_open {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int flags;
 | 
			
		||||
	char path[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_set_master {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int set_master;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
gboolean meta_weston_launch_set_master (GSocket   *weston_launch,
 | 
			
		||||
					int        drm_fd,
 | 
			
		||||
					gboolean   master,
 | 
			
		||||
					GError   **error);
 | 
			
		||||
int      meta_weston_launch_open_input_device (GSocket     *weston_launch,
 | 
			
		||||
					       const char  *name,
 | 
			
		||||
					       int          flags,
 | 
			
		||||
					       GError     **error);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										33
									
								
								src/wayland/meta-xwayland-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/wayland/meta-xwayland-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_XWAYLAND_PRIVATE_H
 | 
			
		||||
#define META_XWAYLAND_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_xwayland_start (MetaWaylandCompositor *compositor);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_xwayland_stop (MetaWaylandCompositor *compositor);
 | 
			
		||||
 | 
			
		||||
#endif /* META_XWAYLAND_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										456
									
								
								src/wayland/meta-xwayland.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										456
									
								
								src/wayland/meta-xwayland.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,456 @@
 | 
			
		||||
/*
 | 
			
		||||
 * X Wayland Support
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2013 Intel Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include "meta-xwayland-private.h"
 | 
			
		||||
#include "meta-window-actor-private.h"
 | 
			
		||||
#include "xserver-server-protocol.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
xserver_set_window_id (struct wl_client *client,
 | 
			
		||||
                       struct wl_resource *compositor_resource,
 | 
			
		||||
                       struct wl_resource *surface_resource,
 | 
			
		||||
                       guint32 xid)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor =
 | 
			
		||||
    wl_resource_get_user_data (compositor_resource);
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
 | 
			
		||||
  MetaDisplay *display = meta_get_display ();
 | 
			
		||||
  MetaWindow *window;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (surface->xid == None);
 | 
			
		||||
 | 
			
		||||
  surface->xid = xid;
 | 
			
		||||
 | 
			
		||||
  window  = meta_display_lookup_x_window (display, xid);
 | 
			
		||||
  if (window)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWindowActor *window_actor =
 | 
			
		||||
        META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
 | 
			
		||||
 | 
			
		||||
      meta_window_actor_set_wayland_surface (window_actor, surface);
 | 
			
		||||
 | 
			
		||||
      surface->window = window;
 | 
			
		||||
      window->surface = surface;
 | 
			
		||||
 | 
			
		||||
      /* If the window is already meant to have focus then the
 | 
			
		||||
       * original attempt to call this in response to the FocusIn
 | 
			
		||||
       * event will have been lost because there was no surface
 | 
			
		||||
       * yet. */
 | 
			
		||||
      if (window->has_focus)
 | 
			
		||||
        meta_wayland_compositor_set_input_focus (compositor, window);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct xserver_interface xserver_implementation = {
 | 
			
		||||
    xserver_set_window_id
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bind_xserver (struct wl_client *client,
 | 
			
		||||
	      void *data,
 | 
			
		||||
              guint32 version,
 | 
			
		||||
              guint32 id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = data;
 | 
			
		||||
 | 
			
		||||
  /* If it's a different client than the xserver we launched,
 | 
			
		||||
   * don't start the wm. */
 | 
			
		||||
  if (client != compositor->xwayland_client)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  compositor->xserver_resource =
 | 
			
		||||
    wl_resource_create (client, &xserver_interface, version, id);
 | 
			
		||||
  wl_resource_set_implementation (compositor->xserver_resource,
 | 
			
		||||
				  &xserver_implementation, compositor, NULL);
 | 
			
		||||
 | 
			
		||||
  wl_resource_post_event (compositor->xserver_resource,
 | 
			
		||||
                          XSERVER_LISTEN_SOCKET,
 | 
			
		||||
                          compositor->xwayland_abstract_fd);
 | 
			
		||||
 | 
			
		||||
  wl_resource_post_event (compositor->xserver_resource,
 | 
			
		||||
                          XSERVER_LISTEN_SOCKET,
 | 
			
		||||
                          compositor->xwayland_unix_fd);
 | 
			
		||||
 | 
			
		||||
  /* Make sure xwayland will recieve the above sockets in a finite
 | 
			
		||||
   * time before unblocking the initialization mainloop since we are
 | 
			
		||||
   * then going to immediately try and connect to those as the window
 | 
			
		||||
   * manager. */
 | 
			
		||||
  wl_client_flush (client);
 | 
			
		||||
 | 
			
		||||
  /* At this point xwayland is all setup to start accepting
 | 
			
		||||
   * connections so we can quit the transient initialization mainloop
 | 
			
		||||
   * and unblock meta_wayland_init() to continue initializing mutter.
 | 
			
		||||
   * */
 | 
			
		||||
  g_main_loop_quit (compositor->init_loop);
 | 
			
		||||
  compositor->init_loop = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
create_lockfile (int display, int *display_out)
 | 
			
		||||
{
 | 
			
		||||
  char *filename;
 | 
			
		||||
  int size;
 | 
			
		||||
  char pid[11];
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  do
 | 
			
		||||
    {
 | 
			
		||||
      char *end;
 | 
			
		||||
      pid_t other;
 | 
			
		||||
 | 
			
		||||
      filename = g_strdup_printf ("/tmp/.X%d-lock", display);
 | 
			
		||||
      fd = open (filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
 | 
			
		||||
 | 
			
		||||
      if (fd < 0 && errno == EEXIST)
 | 
			
		||||
        {
 | 
			
		||||
          fd = open (filename, O_CLOEXEC, O_RDONLY);
 | 
			
		||||
          if (fd < 0 || read (fd, pid, 11) != 11)
 | 
			
		||||
            {
 | 
			
		||||
              const char *msg = strerror (errno);
 | 
			
		||||
              g_warning ("can't read lock file %s: %s", filename, msg);
 | 
			
		||||
              g_free (filename);
 | 
			
		||||
 | 
			
		||||
              /* ignore error and try the next display number */
 | 
			
		||||
              display++;
 | 
			
		||||
              continue;
 | 
			
		||||
          }
 | 
			
		||||
          close (fd);
 | 
			
		||||
 | 
			
		||||
          other = strtol (pid, &end, 0);
 | 
			
		||||
          if (end != pid + 10)
 | 
			
		||||
            {
 | 
			
		||||
              g_warning ("can't parse lock file %s", filename);
 | 
			
		||||
              g_free (filename);
 | 
			
		||||
 | 
			
		||||
              /* ignore error and try the next display number */
 | 
			
		||||
              display++;
 | 
			
		||||
              continue;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (kill (other, 0) < 0 && errno == ESRCH)
 | 
			
		||||
            {
 | 
			
		||||
              g_warning ("unlinking stale lock file %s", filename);
 | 
			
		||||
              if (unlink (filename) < 0)
 | 
			
		||||
                {
 | 
			
		||||
                  const char *msg = strerror (errno);
 | 
			
		||||
                  g_warning ("failed to unlink stale lock file: %s", msg);
 | 
			
		||||
                  display++;
 | 
			
		||||
                }
 | 
			
		||||
              g_free (filename);
 | 
			
		||||
              continue;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          g_free (filename);
 | 
			
		||||
          display++;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
      else if (fd < 0)
 | 
			
		||||
        {
 | 
			
		||||
          const char *msg = strerror (errno);
 | 
			
		||||
          g_warning ("failed to create lock file %s: %s", filename , msg);
 | 
			
		||||
          g_free (filename);
 | 
			
		||||
          return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  while (1);
 | 
			
		||||
 | 
			
		||||
  /* Subtle detail: we use the pid of the wayland compositor, not the xserver
 | 
			
		||||
   * in the lock file. */
 | 
			
		||||
  size = snprintf (pid, 11, "%10d\n", getpid ());
 | 
			
		||||
  if (size != 11 || write (fd, pid, 11) != 11)
 | 
			
		||||
    {
 | 
			
		||||
      unlink (filename);
 | 
			
		||||
      close (fd);
 | 
			
		||||
      g_warning ("failed to write pid to lock file %s", filename);
 | 
			
		||||
      g_free (filename);
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  close (fd);
 | 
			
		||||
 | 
			
		||||
  *display_out = display;
 | 
			
		||||
  return filename;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
bind_to_abstract_socket (int display)
 | 
			
		||||
{
 | 
			
		||||
  struct sockaddr_un addr;
 | 
			
		||||
  socklen_t size, name_size;
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
 | 
			
		||||
  if (fd < 0)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  addr.sun_family = AF_LOCAL;
 | 
			
		||||
  name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
 | 
			
		||||
                        "%c/tmp/.X11-unix/X%d", 0, display);
 | 
			
		||||
  size = offsetof (struct sockaddr_un, sun_path) + name_size;
 | 
			
		||||
  if (bind (fd, (struct sockaddr *) &addr, size) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("failed to bind to @%s: %s\n",
 | 
			
		||||
                 addr.sun_path + 1, strerror (errno));
 | 
			
		||||
      close (fd);
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (listen (fd, 1) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      close (fd);
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
bind_to_unix_socket (int display)
 | 
			
		||||
{
 | 
			
		||||
  struct sockaddr_un addr;
 | 
			
		||||
  socklen_t size, name_size;
 | 
			
		||||
  int fd;
 | 
			
		||||
 | 
			
		||||
  fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
 | 
			
		||||
  if (fd < 0)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  addr.sun_family = AF_LOCAL;
 | 
			
		||||
  name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
 | 
			
		||||
                        "/tmp/.X11-unix/X%d", display) + 1;
 | 
			
		||||
  size = offsetof (struct sockaddr_un, sun_path) + name_size;
 | 
			
		||||
  unlink (addr.sun_path);
 | 
			
		||||
  if (bind (fd, (struct sockaddr *) &addr, size) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      char *msg = strerror (errno);
 | 
			
		||||
      g_warning ("failed to bind to %s (%s)\n", addr.sun_path, msg);
 | 
			
		||||
      close (fd);
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (listen (fd, 1) < 0) {
 | 
			
		||||
      unlink (addr.sun_path);
 | 
			
		||||
      close (fd);
 | 
			
		||||
      return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
uncloexec_and_setpgid (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  int fd = GPOINTER_TO_INT (user_data);
 | 
			
		||||
 | 
			
		||||
  /* Make sure the client end of the socket pair doesn't get closed
 | 
			
		||||
   * when we exec xwayland. */
 | 
			
		||||
  int flags = fcntl (fd, F_GETFD);
 | 
			
		||||
  if (flags != -1)
 | 
			
		||||
    fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC);
 | 
			
		||||
 | 
			
		||||
  /* Put this process in a background process group, so that Ctrl-C
 | 
			
		||||
     goes to mutter only */
 | 
			
		||||
  setpgid (0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
xserver_died (GPid     pid,
 | 
			
		||||
              gint     status,
 | 
			
		||||
              gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  if (!WIFEXITED (status))
 | 
			
		||||
    g_error ("X Wayland crashed; aborting");
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* For now we simply abort if we see the server exit.
 | 
			
		||||
       *
 | 
			
		||||
       * In the future X will only be loaded lazily for legacy X support
 | 
			
		||||
       * but for now it's a hard requirement. */
 | 
			
		||||
      g_error ("Spurious exit of X Wayland server");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
x_io_error (Display *display)
 | 
			
		||||
{
 | 
			
		||||
  g_error ("Connection to xwayland lost");
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_xwayland_start (MetaWaylandCompositor *compositor)
 | 
			
		||||
{
 | 
			
		||||
  int display = 0;
 | 
			
		||||
  char *lockfile = NULL;
 | 
			
		||||
  int sp[2];
 | 
			
		||||
  pid_t pid;
 | 
			
		||||
  char **env;
 | 
			
		||||
  char *fd_string;
 | 
			
		||||
  char *display_name;
 | 
			
		||||
  char *args[11];
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  wl_global_create (compositor->wayland_display,
 | 
			
		||||
		    &xserver_interface, 1,
 | 
			
		||||
		    compositor, bind_xserver);
 | 
			
		||||
 | 
			
		||||
  do
 | 
			
		||||
    {
 | 
			
		||||
      lockfile = create_lockfile (display, &display);
 | 
			
		||||
      if (!lockfile)
 | 
			
		||||
        {
 | 
			
		||||
         g_warning ("Failed to create an X lock file");
 | 
			
		||||
         return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      compositor->xwayland_abstract_fd = bind_to_abstract_socket (display);
 | 
			
		||||
      if (compositor->xwayland_abstract_fd < 0)
 | 
			
		||||
        {
 | 
			
		||||
          unlink (lockfile);
 | 
			
		||||
 | 
			
		||||
          if (errno == EADDRINUSE)
 | 
			
		||||
            {
 | 
			
		||||
              display++;
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      compositor->xwayland_unix_fd = bind_to_unix_socket (display);
 | 
			
		||||
      if (compositor->xwayland_abstract_fd < 0)
 | 
			
		||||
        {
 | 
			
		||||
          unlink (lockfile);
 | 
			
		||||
          close (compositor->xwayland_abstract_fd);
 | 
			
		||||
          return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  while (1);
 | 
			
		||||
 | 
			
		||||
  compositor->xwayland_display_index = display;
 | 
			
		||||
  compositor->xwayland_lockfile = lockfile;
 | 
			
		||||
 | 
			
		||||
  /* We want xwayland to be a wayland client so we make a socketpair to setup a
 | 
			
		||||
   * wayland protocol connection. */
 | 
			
		||||
  if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sp) < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("socketpair failed\n");
 | 
			
		||||
      unlink (lockfile);
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  env = g_get_environ ();
 | 
			
		||||
  fd_string = g_strdup_printf ("%d", sp[1]);
 | 
			
		||||
  env = g_environ_setenv (env, "WAYLAND_SOCKET", fd_string, TRUE);
 | 
			
		||||
  g_free (fd_string);
 | 
			
		||||
 | 
			
		||||
  display_name = g_strdup_printf (":%d",
 | 
			
		||||
                                  compositor->xwayland_display_index);
 | 
			
		||||
 | 
			
		||||
  args[0] = XWAYLAND_PATH;
 | 
			
		||||
  args[1] = display_name;
 | 
			
		||||
  args[2] = "-wayland";
 | 
			
		||||
  args[3] = "-rootless";
 | 
			
		||||
  args[4] = "-retro";
 | 
			
		||||
  args[5] = "-noreset";
 | 
			
		||||
  args[6] = "-logfile";
 | 
			
		||||
  args[7] = g_build_filename (g_get_user_cache_dir (), "xwayland.log", NULL);
 | 
			
		||||
  args[8] = "-nolisten";
 | 
			
		||||
  args[9] = "all";
 | 
			
		||||
  args[10] = NULL;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  if (g_spawn_async (NULL, /* cwd */
 | 
			
		||||
                     args,
 | 
			
		||||
                     env,
 | 
			
		||||
                     G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
 | 
			
		||||
                     G_SPAWN_DO_NOT_REAP_CHILD |
 | 
			
		||||
                     G_SPAWN_STDOUT_TO_DEV_NULL |
 | 
			
		||||
                     G_SPAWN_STDERR_TO_DEV_NULL,
 | 
			
		||||
                     uncloexec_and_setpgid,
 | 
			
		||||
                     GINT_TO_POINTER (sp[1]),
 | 
			
		||||
                     &pid,
 | 
			
		||||
                     &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_message ("forked X server, pid %d\n", pid);
 | 
			
		||||
 | 
			
		||||
      close (sp[1]);
 | 
			
		||||
      compositor->xwayland_client =
 | 
			
		||||
        wl_client_create (compositor->wayland_display, sp[0]);
 | 
			
		||||
 | 
			
		||||
      compositor->xwayland_pid = pid;
 | 
			
		||||
      g_child_watch_add (pid, xserver_died, NULL);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_error ("Failed to fork for xwayland server: %s", error->message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_strfreev (env);
 | 
			
		||||
  g_free (display_name);
 | 
			
		||||
 | 
			
		||||
  /* We need to run a mainloop until we know xwayland has a binding
 | 
			
		||||
   * for our xserver interface at which point we can assume it's
 | 
			
		||||
   * ready to start accepting connections. */
 | 
			
		||||
  compositor->init_loop = g_main_loop_new (NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
  g_main_loop_run (compositor->init_loop);
 | 
			
		||||
 | 
			
		||||
  /* We install an X IO error handler in addition to the child watch,
 | 
			
		||||
     because after Xlib connects our child watch may not be called soon
 | 
			
		||||
     enough, and therefore we won't crash when X exits (and most important
 | 
			
		||||
     we won't reset the tty).
 | 
			
		||||
  */
 | 
			
		||||
  XSetIOErrorHandler (x_io_error);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_xwayland_stop (MetaWaylandCompositor *compositor)
 | 
			
		||||
{
 | 
			
		||||
  char path[256];
 | 
			
		||||
 | 
			
		||||
  snprintf (path, sizeof path, "/tmp/.X%d-lock",
 | 
			
		||||
            compositor->xwayland_display_index);
 | 
			
		||||
  unlink (path);
 | 
			
		||||
  snprintf (path, sizeof path, "/tmp/.X11-unix/X%d",
 | 
			
		||||
            compositor->xwayland_display_index);
 | 
			
		||||
  unlink (path);
 | 
			
		||||
 | 
			
		||||
  unlink (compositor->xwayland_lockfile);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										703
									
								
								src/wayland/weston-launch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										703
									
								
								src/wayland/weston-launch.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,703 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2012 Benjamin Franzke
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <error.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/signalfd.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <linux/vt.h>
 | 
			
		||||
#include <linux/major.h>
 | 
			
		||||
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
#include <security/pam_appl.h>
 | 
			
		||||
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SYSTEMD_LOGIN
 | 
			
		||||
#include <systemd/sd-login.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "weston-launch.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_ARGV_SIZE 256
 | 
			
		||||
 | 
			
		||||
struct weston_launch {
 | 
			
		||||
	struct pam_conv pc;
 | 
			
		||||
	pam_handle_t *ph;
 | 
			
		||||
	int tty;
 | 
			
		||||
	int ttynr;
 | 
			
		||||
	int sock[2];
 | 
			
		||||
	struct passwd *pw;
 | 
			
		||||
 | 
			
		||||
	int signalfd;
 | 
			
		||||
 | 
			
		||||
	pid_t child;
 | 
			
		||||
	int verbose;
 | 
			
		||||
	char *new_user;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union cmsg_data { unsigned char b[4]; int fd; };
 | 
			
		||||
 | 
			
		||||
static gid_t *
 | 
			
		||||
read_groups(void)
 | 
			
		||||
{
 | 
			
		||||
	int n;
 | 
			
		||||
	gid_t *groups;
 | 
			
		||||
	
 | 
			
		||||
	n = getgroups(0, NULL);
 | 
			
		||||
 | 
			
		||||
	if (n < 0) {
 | 
			
		||||
		fprintf(stderr, "Unable to retrieve groups: %m\n");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	groups = malloc(n * sizeof(gid_t));
 | 
			
		||||
	if (!groups)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (getgroups(n, groups) < 0) {
 | 
			
		||||
		fprintf(stderr, "Unable to retrieve groups: %m\n");
 | 
			
		||||
		free(groups);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return groups;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
weston_launch_allowed(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct group *gr;
 | 
			
		||||
	gid_t *groups;
 | 
			
		||||
	int i;
 | 
			
		||||
#ifdef HAVE_SYSTEMD_LOGIN
 | 
			
		||||
	char *session, *seat;
 | 
			
		||||
	int err;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (getuid() == 0)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	gr = getgrnam("weston-launch");
 | 
			
		||||
	if (gr) {
 | 
			
		||||
		groups = read_groups();
 | 
			
		||||
		if (groups) {
 | 
			
		||||
			for (i = 0; groups[i]; ++i) {
 | 
			
		||||
				if (groups[i] == gr->gr_gid) {
 | 
			
		||||
					free(groups);
 | 
			
		||||
					return 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			free(groups);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SYSTEMD_LOGIN
 | 
			
		||||
	err = sd_pid_get_session(getpid(), &session);
 | 
			
		||||
	if (err == 0 && session) {
 | 
			
		||||
		if (sd_session_is_active(session) &&
 | 
			
		||||
		    sd_session_get_seat(session, &seat) == 0) {
 | 
			
		||||
			free(seat);
 | 
			
		||||
			free(session);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		free(session);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
pam_conversation_fn(int msg_count,
 | 
			
		||||
		    const struct pam_message **messages,
 | 
			
		||||
		    struct pam_response **responses,
 | 
			
		||||
		    void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	return PAM_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_pam(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	wl->pc.conv = pam_conversation_fn;
 | 
			
		||||
	wl->pc.appdata_ptr = wl;
 | 
			
		||||
 | 
			
		||||
	err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
 | 
			
		||||
	if (err != PAM_SUCCESS) {
 | 
			
		||||
		fprintf(stderr, "failed to start pam transaction: %d: %s\n",
 | 
			
		||||
			err, pam_strerror(wl->ph, err));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
 | 
			
		||||
	if (err != PAM_SUCCESS) {
 | 
			
		||||
		fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
 | 
			
		||||
			err, pam_strerror(wl->ph, err));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = pam_open_session(wl->ph, 0);
 | 
			
		||||
	if (err != PAM_SUCCESS) {
 | 
			
		||||
		fprintf(stderr, "failed to open pam session: %d: %s\n",
 | 
			
		||||
			err, pam_strerror(wl->ph, err));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_launcher_socket(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
 | 
			
		||||
		error(1, errno, "socketpair failed");
 | 
			
		||||
	
 | 
			
		||||
	fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_signals(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	sigset_t mask;
 | 
			
		||||
	struct sigaction sa;
 | 
			
		||||
 | 
			
		||||
	memset(&sa, 0, sizeof sa);
 | 
			
		||||
	sa.sa_handler = SIG_DFL;
 | 
			
		||||
	sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
 | 
			
		||||
	ret = sigaction(SIGCHLD, &sa, NULL);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
 | 
			
		||||
	sa.sa_handler = SIG_IGN;
 | 
			
		||||
	sa.sa_flags = 0;
 | 
			
		||||
	sigaction(SIGHUP, &sa, NULL);
 | 
			
		||||
 | 
			
		||||
	ret = sigemptyset(&mask);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
	sigaddset(&mask, SIGCHLD);
 | 
			
		||||
	sigaddset(&mask, SIGINT);
 | 
			
		||||
	sigaddset(&mask, SIGTERM);
 | 
			
		||||
	ret = sigprocmask(SIG_BLOCK, &mask, NULL);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
 | 
			
		||||
	wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
 | 
			
		||||
	if (wl->signalfd < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
setenv_fd(const char *env, int fd)
 | 
			
		||||
{
 | 
			
		||||
	char buf[32];
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof buf, "%d", fd);
 | 
			
		||||
	setenv(env, buf, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	struct cmsghdr *cmsg;
 | 
			
		||||
	struct weston_launcher_set_master *message;
 | 
			
		||||
	union cmsg_data *data;
 | 
			
		||||
 | 
			
		||||
	if (len != sizeof(*message)) {
 | 
			
		||||
		error(0, 0, "missing value in setmaster request");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
 | 
			
		||||
	cmsg = CMSG_FIRSTHDR(msg);
 | 
			
		||||
	if (!cmsg ||
 | 
			
		||||
	    cmsg->cmsg_level != SOL_SOCKET ||
 | 
			
		||||
	    cmsg->cmsg_type != SCM_RIGHTS) {
 | 
			
		||||
		error(0, 0, "invalid control message");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data = (union cmsg_data *) CMSG_DATA(cmsg);
 | 
			
		||||
	if (data->fd == -1) {
 | 
			
		||||
		error(0, 0, "missing drm fd in socket request");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (message->set_master)
 | 
			
		||||
		ret = drmSetMaster(data->fd);
 | 
			
		||||
	else
 | 
			
		||||
		ret = drmDropMaster(data->fd);
 | 
			
		||||
 | 
			
		||||
	close(data->fd);
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "weston-launch: %sMaster, ret: %d, fd: %d\n",
 | 
			
		||||
			message->set_master ? "set" : "drop", ret, data->fd);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &ret, sizeof ret, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
	int fd = -1, ret = -1;
 | 
			
		||||
	char control[CMSG_SPACE(sizeof(fd))];
 | 
			
		||||
	struct cmsghdr *cmsg;
 | 
			
		||||
	struct stat s;
 | 
			
		||||
	struct msghdr nmsg;
 | 
			
		||||
	struct iovec iov;
 | 
			
		||||
	struct weston_launcher_open *message;
 | 
			
		||||
	union cmsg_data *data;
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
	if ((size_t)len < sizeof(*message))
 | 
			
		||||
		goto err0;
 | 
			
		||||
 | 
			
		||||
	/* Ensure path is null-terminated */
 | 
			
		||||
	((char *) message)[len-1] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (stat(message->path, &s) < 0)
 | 
			
		||||
		goto err0;
 | 
			
		||||
 | 
			
		||||
	fd = open(message->path, message->flags);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		fprintf(stderr, "Error opening device %s: %m\n",
 | 
			
		||||
			message->path);
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (major(s.st_rdev) != INPUT_MAJOR) {
 | 
			
		||||
		close(fd);
 | 
			
		||||
		fd = -1;
 | 
			
		||||
		fprintf(stderr, "Device %s is not an input device\n",
 | 
			
		||||
			message->path);
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
err0:
 | 
			
		||||
	memset(&nmsg, 0, sizeof nmsg);
 | 
			
		||||
	nmsg.msg_iov = &iov;
 | 
			
		||||
	nmsg.msg_iovlen = 1;
 | 
			
		||||
	if (fd != -1) {
 | 
			
		||||
		nmsg.msg_control = control;
 | 
			
		||||
		nmsg.msg_controllen = sizeof control;
 | 
			
		||||
		cmsg = CMSG_FIRSTHDR(&nmsg);
 | 
			
		||||
		cmsg->cmsg_level = SOL_SOCKET;
 | 
			
		||||
		cmsg->cmsg_type = SCM_RIGHTS;
 | 
			
		||||
		cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
 | 
			
		||||
		data = (union cmsg_data *) CMSG_DATA(cmsg);
 | 
			
		||||
		data->fd = fd;
 | 
			
		||||
		nmsg.msg_controllen = cmsg->cmsg_len;
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
	iov.iov_base = &ret;
 | 
			
		||||
	iov.iov_len = sizeof ret;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
 | 
			
		||||
			message->path, ret, fd);
 | 
			
		||||
	do {
 | 
			
		||||
		len = sendmsg(wl->sock[0], &nmsg, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	close(fd);
 | 
			
		||||
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_socket_msg(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	char control[CMSG_SPACE(sizeof(int))];
 | 
			
		||||
	char buf[BUFSIZ];
 | 
			
		||||
	struct msghdr msg;
 | 
			
		||||
	struct iovec iov;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	ssize_t len;
 | 
			
		||||
	struct weston_launcher_message *message;
 | 
			
		||||
 | 
			
		||||
	memset(&msg, 0, sizeof(msg));
 | 
			
		||||
	iov.iov_base = buf;
 | 
			
		||||
	iov.iov_len  = sizeof buf;
 | 
			
		||||
	msg.msg_iov = &iov;
 | 
			
		||||
	msg.msg_iovlen = 1;
 | 
			
		||||
	msg.msg_control = control;
 | 
			
		||||
	msg.msg_controllen = sizeof control;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		len = recvmsg(wl->sock[0], &msg, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	if (len < 1)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	message = (void *) buf;
 | 
			
		||||
	switch (message->opcode) {
 | 
			
		||||
	case WESTON_LAUNCHER_OPEN:
 | 
			
		||||
		ret = handle_open(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_DRM_SET_MASTER:
 | 
			
		||||
		ret = handle_setmaster(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
quit(struct weston_launch *wl, int status)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	close(wl->signalfd);
 | 
			
		||||
	close(wl->sock[0]);
 | 
			
		||||
 | 
			
		||||
	if (wl->new_user) {
 | 
			
		||||
		err = pam_close_session(wl->ph, 0);
 | 
			
		||||
		if (err)
 | 
			
		||||
			fprintf(stderr, "pam_close_session failed: %d: %s\n",
 | 
			
		||||
				err, pam_strerror(wl->ph, err));
 | 
			
		||||
		pam_end(wl->ph, err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exit(status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_signal(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct signalfd_siginfo sig;
 | 
			
		||||
	int pid, status, ret;
 | 
			
		||||
 | 
			
		||||
	if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
 | 
			
		||||
		error(0, errno, "reading signalfd failed");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (sig.ssi_signo) {
 | 
			
		||||
	case SIGCHLD:
 | 
			
		||||
		pid = waitpid(-1, &status, 0);
 | 
			
		||||
		if (pid == wl->child) {
 | 
			
		||||
			wl->child = 0;
 | 
			
		||||
			if (WIFEXITED(status))
 | 
			
		||||
				ret = WEXITSTATUS(status);
 | 
			
		||||
			else if (WIFSIGNALED(status))
 | 
			
		||||
				/*
 | 
			
		||||
				 * If weston dies because of signal N, we
 | 
			
		||||
				 * return 10+N. This is distinct from
 | 
			
		||||
				 * weston-launch dying because of a signal
 | 
			
		||||
				 * (128+N).
 | 
			
		||||
				 */
 | 
			
		||||
				ret = 10 + WTERMSIG(status);
 | 
			
		||||
			else
 | 
			
		||||
				ret = 0;
 | 
			
		||||
			quit(wl, ret);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGTERM:
 | 
			
		||||
	case SIGINT:
 | 
			
		||||
		if (wl->child)
 | 
			
		||||
			kill(wl->child, sig.ssi_signo);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_tty(struct weston_launch *wl, const char *tty)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	char *t;
 | 
			
		||||
 | 
			
		||||
	if (!wl->new_user) {
 | 
			
		||||
		wl->tty = STDIN_FILENO;
 | 
			
		||||
	} else if (tty) {
 | 
			
		||||
		t = ttyname(STDIN_FILENO);
 | 
			
		||||
		if (t && strcmp(t, tty) == 0)
 | 
			
		||||
			wl->tty = STDIN_FILENO;
 | 
			
		||||
		else
 | 
			
		||||
			wl->tty = open(tty, O_RDWR | O_NOCTTY);
 | 
			
		||||
	} else {
 | 
			
		||||
		int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
 | 
			
		||||
		char filename[16];
 | 
			
		||||
 | 
			
		||||
		if (tty0 < 0)
 | 
			
		||||
			error(1, errno, "could not open tty0");
 | 
			
		||||
 | 
			
		||||
		if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
 | 
			
		||||
			error(1, errno, "failed to find non-opened console"); 
 | 
			
		||||
 | 
			
		||||
		snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
 | 
			
		||||
		wl->tty = open(filename, O_RDWR | O_NOCTTY);
 | 
			
		||||
		close(tty0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl->tty < 0)
 | 
			
		||||
		error(1, errno, "failed to open tty");
 | 
			
		||||
 | 
			
		||||
	if (tty) {
 | 
			
		||||
		if (fstat(wl->tty, &buf) < 0)
 | 
			
		||||
			error(1, errno, "stat %s failed", tty);
 | 
			
		||||
 | 
			
		||||
		if (major(buf.st_rdev) != TTY_MAJOR)
 | 
			
		||||
			error(1, 0, "invalid tty device: %s", tty);
 | 
			
		||||
 | 
			
		||||
		wl->ttynr = minor(buf.st_rdev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
setup_session(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	char **env;
 | 
			
		||||
	char *term;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (wl->tty != STDIN_FILENO) {
 | 
			
		||||
		if (setsid() < 0)
 | 
			
		||||
			error(1, errno, "setsid failed");
 | 
			
		||||
		if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
 | 
			
		||||
			error(1, errno, "TIOCSCTTY failed - tty is in use");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (setgid(wl->pw->pw_gid) < 0 ||
 | 
			
		||||
#ifdef HAVE_INITGROUPS
 | 
			
		||||
	    initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
 | 
			
		||||
#endif
 | 
			
		||||
	    setuid(wl->pw->pw_uid) < 0)
 | 
			
		||||
		error(1, errno, "dropping privileges failed");
 | 
			
		||||
 | 
			
		||||
	term = getenv("TERM");
 | 
			
		||||
	clearenv();
 | 
			
		||||
	setenv("TERM", term, 1);
 | 
			
		||||
	setenv("USER", wl->pw->pw_name, 1);
 | 
			
		||||
	setenv("LOGNAME", wl->pw->pw_name, 1);
 | 
			
		||||
	setenv("HOME", wl->pw->pw_dir, 1);
 | 
			
		||||
	setenv("SHELL", wl->pw->pw_shell, 1);
 | 
			
		||||
 | 
			
		||||
	env = pam_getenvlist(wl->ph);
 | 
			
		||||
	if (env) {
 | 
			
		||||
		for (i = 0; env[i]; ++i) {
 | 
			
		||||
			if (putenv(env[i]) < 0)
 | 
			
		||||
				error(0, 0, "putenv %s failed", env[i]);
 | 
			
		||||
		}
 | 
			
		||||
		free(env);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	char command[PATH_MAX];
 | 
			
		||||
	char *child_argv[MAX_ARGV_SIZE];
 | 
			
		||||
	sigset_t mask;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		printf("weston-launch: spawned weston with pid: %d\n", getpid());
 | 
			
		||||
	if (wl->new_user)
 | 
			
		||||
		setup_session(wl);
 | 
			
		||||
 | 
			
		||||
	if (wl->tty != STDIN_FILENO)
 | 
			
		||||
		setenv_fd("WESTON_TTY_FD", wl->tty);
 | 
			
		||||
 | 
			
		||||
	setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
 | 
			
		||||
 | 
			
		||||
	unsetenv("DISPLAY");
 | 
			
		||||
 | 
			
		||||
	/* Do not give our signal mask to the new process. */
 | 
			
		||||
	sigemptyset(&mask);
 | 
			
		||||
	sigaddset(&mask, SIGTERM);
 | 
			
		||||
	sigaddset(&mask, SIGCHLD);
 | 
			
		||||
	sigaddset(&mask, SIGINT);
 | 
			
		||||
	sigprocmask(SIG_UNBLOCK, &mask, NULL);
 | 
			
		||||
 | 
			
		||||
	snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
 | 
			
		||||
 | 
			
		||||
	child_argv[0] = wl->pw->pw_shell;
 | 
			
		||||
	child_argv[1] = "-l";
 | 
			
		||||
	child_argv[2] = "-c";
 | 
			
		||||
	child_argv[3] = command;
 | 
			
		||||
	for (i = 0; i < argc; ++i)
 | 
			
		||||
		child_argv[4 + i] = argv[i];
 | 
			
		||||
	child_argv[4 + i] = NULL;
 | 
			
		||||
 | 
			
		||||
	execv(child_argv[0], child_argv);
 | 
			
		||||
	error(1, errno, "exec failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
help(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
 | 
			
		||||
	fprintf(stderr, "  -u, --user      Start session as specified username\n");
 | 
			
		||||
	fprintf(stderr, "  -t, --tty       Start session on alternative tty\n");
 | 
			
		||||
	fprintf(stderr, "  -v, --verbose   Be verbose\n");
 | 
			
		||||
	fprintf(stderr, "  -h, --help      Display this help message\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	struct weston_launch wl;
 | 
			
		||||
	int i, c;
 | 
			
		||||
	char *tty = NULL;
 | 
			
		||||
	struct option opts[] = {
 | 
			
		||||
		{ "user",    required_argument, NULL, 'u' },
 | 
			
		||||
		{ "tty",     required_argument, NULL, 't' },
 | 
			
		||||
		{ "verbose", no_argument,       NULL, 'v' },
 | 
			
		||||
		{ "help",    no_argument,       NULL, 'h' },
 | 
			
		||||
		{ 0,         0,                 NULL,  0  }
 | 
			
		||||
	};	
 | 
			
		||||
 | 
			
		||||
	memset(&wl, 0, sizeof wl);
 | 
			
		||||
 | 
			
		||||
	while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'u':
 | 
			
		||||
			wl.new_user = optarg;
 | 
			
		||||
			if (getuid() != 0)
 | 
			
		||||
				error(1, 0, "Permission denied. -u allowed for root only");
 | 
			
		||||
			break;
 | 
			
		||||
		case 't':
 | 
			
		||||
			tty = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'v':
 | 
			
		||||
			wl.verbose = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			help("weston-launch");
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((argc - optind) > (MAX_ARGV_SIZE - 6))
 | 
			
		||||
		error(1, E2BIG, "Too many arguments to pass to weston");
 | 
			
		||||
 | 
			
		||||
	if (strcmp (argv[optind], "mutter") &&
 | 
			
		||||
	    strcmp (argv[optind], "gnome-shell") &&
 | 
			
		||||
	    strcmp (argv[optind], "gnome-shell-real") && 0)
 | 
			
		||||
		error(1, 0, "mutter-launch can only be used to launch mutter or gnome-shell");
 | 
			
		||||
 | 
			
		||||
	if (wl.new_user)
 | 
			
		||||
		wl.pw = getpwnam(wl.new_user);
 | 
			
		||||
	else
 | 
			
		||||
		wl.pw = getpwuid(getuid());
 | 
			
		||||
	if (wl.pw == NULL)
 | 
			
		||||
		error(1, errno, "failed to get username");
 | 
			
		||||
 | 
			
		||||
	if (!weston_launch_allowed(&wl))
 | 
			
		||||
		error(1, 0, "Permission denied. You should either:\n"
 | 
			
		||||
#ifdef HAVE_SYSTEMD_LOGIN
 | 
			
		||||
		      " - run from an active and local (systemd) session.\n"
 | 
			
		||||
#else
 | 
			
		||||
		      " - enable systemd session support for weston-launch.\n"
 | 
			
		||||
#endif
 | 
			
		||||
		      " - or add yourself to the 'weston-launch' group.");
 | 
			
		||||
 | 
			
		||||
	if (setup_tty(&wl, tty) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (wl.new_user && setup_pam(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (setup_launcher_socket(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (setup_signals(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	wl.child = fork();
 | 
			
		||||
	if (wl.child == -1) {
 | 
			
		||||
		error(1, errno, "fork failed");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl.child == 0)
 | 
			
		||||
		launch_compositor(&wl, argc - optind, argv + optind);
 | 
			
		||||
 | 
			
		||||
	close(wl.sock[1]);
 | 
			
		||||
	if (wl.tty != STDIN_FILENO)
 | 
			
		||||
		close(wl.tty);
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		struct pollfd fds[2];
 | 
			
		||||
		int n;
 | 
			
		||||
 | 
			
		||||
		fds[0].fd = wl.sock[0];
 | 
			
		||||
		fds[0].events = POLLIN;
 | 
			
		||||
		fds[1].fd = wl.signalfd;
 | 
			
		||||
		fds[1].events = POLLIN;
 | 
			
		||||
 | 
			
		||||
		n = poll(fds, 2, -1);
 | 
			
		||||
		if (n < 0)
 | 
			
		||||
			error(0, errno, "poll failed");
 | 
			
		||||
		if (fds[0].revents & POLLIN)
 | 
			
		||||
			handle_socket_msg(&wl);
 | 
			
		||||
		if (fds[1].revents)
 | 
			
		||||
			handle_signal(&wl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/wayland/weston-launch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/wayland/weston-launch.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2012 Benjamin Franzke
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, distribute, and sell this software and
 | 
			
		||||
 * its documentation for any purpose is hereby granted without fee, provided
 | 
			
		||||
 * that the above copyright notice appear in all copies and that both that
 | 
			
		||||
 * copyright notice and this permission notice appear in supporting
 | 
			
		||||
 * documentation, and that the name of the copyright holders not be used in
 | 
			
		||||
 * advertising or publicity pertaining to distribution of the software
 | 
			
		||||
 * without specific, written prior permission.  The copyright holders make
 | 
			
		||||
 * no representations about the suitability of this software for any
 | 
			
		||||
 * purpose.  It is provided "as is" without express or implied warranty.
 | 
			
		||||
 *
 | 
			
		||||
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
			
		||||
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
			
		||||
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 | 
			
		||||
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 | 
			
		||||
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _WESTON_LAUNCH_H_
 | 
			
		||||
#define _WESTON_LAUNCH_H_
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_opcode {
 | 
			
		||||
	WESTON_LAUNCHER_OPEN,
 | 
			
		||||
	WESTON_LAUNCHER_DRM_SET_MASTER
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_message {
 | 
			
		||||
	int opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_open {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int flags;
 | 
			
		||||
	char path[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_set_master {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int set_master;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										283
									
								
								src/xrandr.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								src/xrandr.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
<!DOCTYPE node PUBLIC
 | 
			
		||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
 | 
			
		||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
 | 
			
		||||
<node>
 | 
			
		||||
  <!--
 | 
			
		||||
      org.gnome.Mutter.DisplayConfig:
 | 
			
		||||
      @short_description: display configuration interface
 | 
			
		||||
 | 
			
		||||
      This interface is used by mutter and gnome-settings-daemon
 | 
			
		||||
      to apply multiple monitor configuration.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
  <interface name="org.gnome.Mutter.DisplayConfig">
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        GetResources:
 | 
			
		||||
	@serial: configuration serial
 | 
			
		||||
	@crtcs: available CRTCs
 | 
			
		||||
	@outputs: available outputs
 | 
			
		||||
	@modes: available modes
 | 
			
		||||
	@max_screen_width:
 | 
			
		||||
	@max_screen_height:
 | 
			
		||||
 | 
			
		||||
        Retrieves the current layout of the hardware.
 | 
			
		||||
 | 
			
		||||
        @serial is an unique identifier representing the current state
 | 
			
		||||
        of the screen. It must be passed back to ApplyConfiguration()
 | 
			
		||||
	and will be increased for every configuration change (so that
 | 
			
		||||
	mutter can detect that the new configuration is based on old
 | 
			
		||||
	state).
 | 
			
		||||
 | 
			
		||||
	A CRTC (CRT controller) is a logical monitor, ie a portion
 | 
			
		||||
	of the compositor coordinate space. It might correspond
 | 
			
		||||
	to multiple monitors, when in clone mode, but not that
 | 
			
		||||
	it is possible to implement clone mode also by setting different
 | 
			
		||||
	CRTCs to the same coordinates.
 | 
			
		||||
 | 
			
		||||
	The number of CRTCs represent the maximum number of monitors
 | 
			
		||||
	that can be set to expand and it is a HW constraint; if more
 | 
			
		||||
	monitors are connected,	then necessarily some will clone. This
 | 
			
		||||
	is complementary to the concept of the encoder (not exposed in
 | 
			
		||||
	the API), which groups outputs that necessarily will show the
 | 
			
		||||
	same image (again a HW constraint).
 | 
			
		||||
 | 
			
		||||
	A CRTC is represented by a DBus structure with the following
 | 
			
		||||
	layout:
 | 
			
		||||
	* u ID: the ID in the API of this CRTC
 | 
			
		||||
	* x winsys_id: the low-level ID of this CRTC (which might
 | 
			
		||||
	               be a XID, a KMS handle or something entirely
 | 
			
		||||
		       different)
 | 
			
		||||
	* i x, y, width, height: the geometry of this CRTC
 | 
			
		||||
	                         (might be invalid if the CRTC is not in
 | 
			
		||||
				 use)
 | 
			
		||||
	* i current_mode: the current mode of the CRTC, or -1 if this
 | 
			
		||||
	                  CRTC is not used
 | 
			
		||||
			  Note: the size of the mode will always correspond
 | 
			
		||||
			  to the width and height of the CRTC
 | 
			
		||||
	* u current_transform: the current transform (espressed according
 | 
			
		||||
	                       to the wayland protocol)
 | 
			
		||||
	* au transforms: all possible transforms
 | 
			
		||||
	* a{sv} properties: other high-level properties that affect this
 | 
			
		||||
	                    CRTC; they are not necessarily reflected in
 | 
			
		||||
			    the hardware.
 | 
			
		||||
			    No property is specified in this version of the API.
 | 
			
		||||
 | 
			
		||||
        Note: all geometry information refers to the untransformed
 | 
			
		||||
	display.
 | 
			
		||||
 | 
			
		||||
	An output represents a physical screen, connected somewhere to
 | 
			
		||||
	the computer. Floating connectors are not exposed in the API.
 | 
			
		||||
	An output is a DBus struct with the following fields:
 | 
			
		||||
	* u ID: the ID in the API
 | 
			
		||||
	* x winsys_id: the low-level ID of this output (XID or KMS handle)
 | 
			
		||||
	* i current_crtc: the CRTC that is currently driving this output,
 | 
			
		||||
	                  or -1 if the output is disabled
 | 
			
		||||
	* au possible_crtcs: all CRTCs that can control this output
 | 
			
		||||
	* s name: the name of the connector to which the output is attached
 | 
			
		||||
	          (like VGA1 or HDMI)
 | 
			
		||||
	* au modes: valid modes for this output
 | 
			
		||||
	* au clones: valid clones for this output, ie other outputs that
 | 
			
		||||
	             can be assigned the same CRTC as this one; if you
 | 
			
		||||
	             want to mirror two outputs that don't have each other
 | 
			
		||||
	             in the clone list, you must configure two different
 | 
			
		||||
	             CRTCs for the same geometry
 | 
			
		||||
	* a{sv} properties: other high-level properties that affect this
 | 
			
		||||
	                    output; they are not necessarily reflected in
 | 
			
		||||
			    the hardware.
 | 
			
		||||
			    Known properties:
 | 
			
		||||
                            - "vendor" (s): (readonly) the human readable name
 | 
			
		||||
                                            of the manufacturer
 | 
			
		||||
                            - "product" (s): (readonly) the human readable name
 | 
			
		||||
                                             of the display model
 | 
			
		||||
                            - "serial" (s): (readonly) the serial number of this
 | 
			
		||||
                                            particular hardware part
 | 
			
		||||
			    - "display-name" (s): (readonly) a human readable name
 | 
			
		||||
			                          of this output, to be shown in the UI
 | 
			
		||||
	                    - "backlight" (i): (readonly, use the specific interface)
 | 
			
		||||
                                               the backlight value as a percentage
 | 
			
		||||
                                               (-1 if not supported)
 | 
			
		||||
			    - "primary" (b): whether this output is primary
 | 
			
		||||
			                     or not
 | 
			
		||||
			    - "presentation" (b): whether this output is
 | 
			
		||||
			                          for presentation only
 | 
			
		||||
			    Note: properties might be ignored if not consistenly
 | 
			
		||||
			    applied to all outputs in the same clone group. In
 | 
			
		||||
			    general, it's expected that presentation or primary
 | 
			
		||||
			    outputs will not be cloned.
 | 
			
		||||
 | 
			
		||||
        A mode represents a set of parameters that are applied to
 | 
			
		||||
	each output, such as resolution and refresh rate. It is a separate
 | 
			
		||||
	object so that it can be referenced by CRTCs and outputs.
 | 
			
		||||
	Multiple outputs in the same CRTCs must all have the same mode.
 | 
			
		||||
	A mode is exposed as:
 | 
			
		||||
	* u ID: the ID in the API
 | 
			
		||||
	* x winsys_id: the low-level ID of this mode
 | 
			
		||||
	* u width, height: the resolution
 | 
			
		||||
	* d frequency: refresh rate
 | 
			
		||||
 | 
			
		||||
        Output and modes are read-only objects (except for output properties),
 | 
			
		||||
	they can change only in accordance to HW changes (such as hotplugging
 | 
			
		||||
	a monitor), while CRTCs can be changed with ApplyConfiguration().
 | 
			
		||||
 | 
			
		||||
        XXX: actually, if you insist enough, you can add new modes
 | 
			
		||||
	through xrandr command line or the KMS API, overriding what the
 | 
			
		||||
	kernel driver and the EDID say.
 | 
			
		||||
	Usually, it only matters with old cards with broken drivers, or
 | 
			
		||||
	old monitors with broken EDIDs, but it happens more often with
 | 
			
		||||
	projectors (if for example the kernel driver doesn't add the
 | 
			
		||||
	640x480 - 800x600 - 1024x768 default modes). Probably something
 | 
			
		||||
	that we need to handle in mutter anyway.
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="GetResources">
 | 
			
		||||
      <arg name="serial" direction="out" type="u" />
 | 
			
		||||
      <arg name="crtcs" direction="out" type="a(uxiiiiiuaua{sv})" />
 | 
			
		||||
      <arg name="outputs" direction="out" type="a(uxiausauaua{sv})" />
 | 
			
		||||
      <arg name="modes" direction="out" type="a(uxuud)" />
 | 
			
		||||
      <arg name="max_screen_width" direction="out" type="i" />
 | 
			
		||||
      <arg name="max_screen_height" direction="out" type="i" />
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        ApplyConfiguration:
 | 
			
		||||
	@serial: configuration serial
 | 
			
		||||
	@persistent: whether this configuration should be saved on disk
 | 
			
		||||
	@crtcs: new data for CRTCs
 | 
			
		||||
	@outputs: new data for outputs
 | 
			
		||||
 | 
			
		||||
	Applies the requested configuration changes.
 | 
			
		||||
 | 
			
		||||
	@serial must match the serial from the last GetResources() call,
 | 
			
		||||
	or org.freedesktop.DBus.AccessDenied will be generated.
 | 
			
		||||
	(XXX: a better error maybe?)
 | 
			
		||||
 | 
			
		||||
	If @persistent is true, mutter will attempt to replicate this
 | 
			
		||||
	configuration the next time this HW layout appears.
 | 
			
		||||
	(XXX: or is this gnome-settings-daemon role?)
 | 
			
		||||
 | 
			
		||||
	@crtcs represents the new logical configuration, as a list
 | 
			
		||||
	of structures containing:
 | 
			
		||||
	- u ID: the API ID from the corresponding GetResources() call
 | 
			
		||||
	- i new_mode: the API ID of the new mode to configure the CRTC
 | 
			
		||||
	              with, or -1 if the CRTC should be disabled
 | 
			
		||||
        - i x, y: the new coordinates of the top left corner
 | 
			
		||||
	          the geometry will be completed with the size information
 | 
			
		||||
		  from @new_mode
 | 
			
		||||
        - u transform: the desired transform
 | 
			
		||||
	- au outputs: the API ID of outputs that should be assigned to
 | 
			
		||||
	              this CRTC
 | 
			
		||||
        - a{sv} properties: properties whose value should be changed
 | 
			
		||||
 | 
			
		||||
	Note: CRTCs not referenced in the array will be	disabled.
 | 
			
		||||
 | 
			
		||||
	@outputs represent the output property changes as:
 | 
			
		||||
	- u ID: the API ID of the output to change
 | 
			
		||||
	- a{sv} properties: properties whose value should be changed
 | 
			
		||||
 | 
			
		||||
	Note: both for CRTCs and outputs, properties not included in
 | 
			
		||||
	the dictionary will not be changed.
 | 
			
		||||
 | 
			
		||||
	Note: unrecognized properties will have no effect, but if the
 | 
			
		||||
	configuration change succeeds the property will be reported
 | 
			
		||||
	by the next GetResources() call, and if @persistent is true,
 | 
			
		||||
	it will also be saved to disk.
 | 
			
		||||
 | 
			
		||||
	If the configuration is invalid according to the previous
 | 
			
		||||
	GetResources() call, for example because a CRTC references
 | 
			
		||||
	an output it cannot drive, or not all outputs support the
 | 
			
		||||
	chosen mode, the error org.freedesktop.DBus.InvalidArgs will
 | 
			
		||||
	be generated.
 | 
			
		||||
 | 
			
		||||
	If the configuration cannot be applied for any other reason
 | 
			
		||||
	(eg. the screen size would exceed texture limits), the error
 | 
			
		||||
	org.freedesktop.DBus.Error.LimitsExceeded will be generated.
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="ApplyConfiguration">
 | 
			
		||||
      <arg name="serial" direction="in" type="u" />
 | 
			
		||||
      <arg name="persistent" direction="in" type="b" />
 | 
			
		||||
      <arg name="crtcs" direction="in" type="a(uiiiuaua{sv})" />
 | 
			
		||||
      <arg name="outputs" direction="in" type="a(ua{sv})" />
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        ChangeBacklight:
 | 
			
		||||
	@serial: configuration serial
 | 
			
		||||
	@output: the API id of the output
 | 
			
		||||
	@value: the new backlight value
 | 
			
		||||
 | 
			
		||||
	Changes the backlight of @output to @value, which is
 | 
			
		||||
	expressed as a percentage and rounded to the HW limits.
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="ChangeBacklight">
 | 
			
		||||
      <arg name="serial" direction="in" type="u" />
 | 
			
		||||
      <arg name="output" direction="in" type="u" />
 | 
			
		||||
      <arg name="value" direction="in" type="i" />
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        GetCrtcGamma:
 | 
			
		||||
	@serial: configuration serial
 | 
			
		||||
	@crtc: API id of the crtc
 | 
			
		||||
	@red: red gamma ramp
 | 
			
		||||
	@green: green gamma ramp
 | 
			
		||||
	@blue: blue gamma ramp
 | 
			
		||||
 | 
			
		||||
	Requests the current gamma ramps of @crtc.
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="GetCrtcGamma">
 | 
			
		||||
      <arg name="serial" direction="in" type="u" />
 | 
			
		||||
      <arg name="crtc" direction="in" type="u" />
 | 
			
		||||
      <arg name="red" direction="out" type="aq" />
 | 
			
		||||
      <arg name="green" direction="out" type="aq" />
 | 
			
		||||
      <arg name="blue" direction="out" type="aq" />
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        SetCrtcGamma:
 | 
			
		||||
	@serial: configuration serial
 | 
			
		||||
	@crtc: API id of the crtc
 | 
			
		||||
	@red: red gamma ramp
 | 
			
		||||
	@green: green gamma ramp
 | 
			
		||||
	@blue: blue gamma ramp
 | 
			
		||||
 | 
			
		||||
	Changes the gamma ramps of @crtc.
 | 
			
		||||
    -->
 | 
			
		||||
    <method name="SetCrtcGamma">
 | 
			
		||||
      <arg name="serial" direction="in" type="u" />
 | 
			
		||||
      <arg name="crtc" direction="in" type="u" />
 | 
			
		||||
      <arg name="red" direction="in" type="aq" />
 | 
			
		||||
      <arg name="green" direction="in" type="aq" />
 | 
			
		||||
      <arg name="blue" direction="in" type="aq" />
 | 
			
		||||
    </method>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
        PowerSaveMode:
 | 
			
		||||
 | 
			
		||||
	Contains the current power saving mode for the screen, and
 | 
			
		||||
	allows changing it.
 | 
			
		||||
 | 
			
		||||
        Possible values:
 | 
			
		||||
	- 0: on
 | 
			
		||||
	- 1: standby
 | 
			
		||||
	- 2: suspend
 | 
			
		||||
	- 3: off
 | 
			
		||||
	- -1: unknown (unsupported)
 | 
			
		||||
 | 
			
		||||
        A client should not attempt to change the powersave mode
 | 
			
		||||
	from -1 (unknown) to any other value, and viceversa.
 | 
			
		||||
	Note that the actual effects of the different values
 | 
			
		||||
	depend on the hardware and the kernel driver in use, and
 | 
			
		||||
	it's perfectly possible that all values different than on
 | 
			
		||||
	have the same effect.
 | 
			
		||||
	Also, setting the PowerSaveMode to 3 (off) may or may
 | 
			
		||||
	not have the same effect as disabling all outputs by
 | 
			
		||||
	setting no CRTC on them with ApplyConfiguration(), and
 | 
			
		||||
	may or may not cause a configuration change.
 | 
			
		||||
 | 
			
		||||
        Also note that this property might become out of date
 | 
			
		||||
	if changed through different means (for example using the
 | 
			
		||||
	XRandR interface directly).
 | 
			
		||||
    -->
 | 
			
		||||
    <property name="PowerSaveMode" type="i" access="readwrite" />
 | 
			
		||||
  </interface>
 | 
			
		||||
</node>
 | 
			
		||||
		Reference in New Issue
	
	Block a user