Compare commits
	
		
			115 Commits
		
	
	
		
			3.18.3
			...
			wip/garnac
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9f35b5816a | ||
| 
						 | 
					63c91f9d4f | ||
| 
						 | 
					aaa02440be | ||
| 
						 | 
					9611661154 | ||
| 
						 | 
					a70a2c3744 | ||
| 
						 | 
					bc47b19c3f | ||
| 
						 | 
					bc1dd1cee4 | ||
| 
						 | 
					495c89401a | ||
| 
						 | 
					e2efc85b08 | ||
| 
						 | 
					020ae58fe4 | ||
| 
						 | 
					525644059d | ||
| 
						 | 
					f0f638d2bd | ||
| 
						 | 
					bc8ec2d90d | ||
| 
						 | 
					5b0eabec51 | ||
| 
						 | 
					50099c4c10 | ||
| 
						 | 
					55eef2deb3 | ||
| 
						 | 
					f9db65f47f | ||
| 
						 | 
					a809055470 | ||
| 
						 | 
					247909e161 | ||
| 
						 | 
					e5ce6192f4 | ||
| 
						 | 
					7adbb58736 | ||
| 
						 | 
					0165cb6974 | ||
| 
						 | 
					3cdcd3e9c1 | ||
| 
						 | 
					6fc51e3723 | ||
| 
						 | 
					af45a50cb1 | ||
| 
						 | 
					72d6efc0d5 | ||
| 
						 | 
					e0ffef06dd | ||
| 
						 | 
					d5b69bcd54 | ||
| 
						 | 
					ac8fe2d9b2 | ||
| 
						 | 
					e7a88dc6b2 | ||
| 
						 | 
					bcdda506e1 | ||
| 
						 | 
					9b26694bbc | ||
| 
						 | 
					f053c09083 | ||
| 
						 | 
					ec9abaf1ef | ||
| 
						 | 
					6b88420465 | ||
| 
						 | 
					fc0a834abb | ||
| 
						 | 
					e30010b9f0 | ||
| 
						 | 
					935d76ba04 | ||
| 
						 | 
					cc013e1daa | ||
| 
						 | 
					a7a376ae1f | ||
| 
						 | 
					5e57af6286 | ||
| 
						 | 
					42b3a34f7b | ||
| 
						 | 
					19d814c887 | ||
| 
						 | 
					46eb682c83 | ||
| 
						 | 
					3aea8d8ce6 | ||
| 
						 | 
					40c3c69435 | ||
| 
						 | 
					8071e5b149 | ||
| 
						 | 
					8a481b3e10 | ||
| 
						 | 
					50e3e3b929 | ||
| 
						 | 
					2c7ef2269f | ||
| 
						 | 
					8bded7d497 | ||
| 
						 | 
					9ebe3419c3 | ||
| 
						 | 
					9385c835b8 | ||
| 
						 | 
					efef0c993b | ||
| 
						 | 
					3a2cd3389a | ||
| 
						 | 
					88acfb8e60 | ||
| 
						 | 
					8e22dce5d7 | ||
| 
						 | 
					e0906a77aa | ||
| 
						 | 
					053f5088df | ||
| 
						 | 
					75b992c7d0 | ||
| 
						 | 
					213f0fa160 | ||
| 
						 | 
					5054b2a99c | ||
| 
						 | 
					d455de32a0 | ||
| 
						 | 
					e7390cff83 | ||
| 
						 | 
					49ea6486e2 | ||
| 
						 | 
					996aeaef41 | ||
| 
						 | 
					a27b2597b9 | ||
| 
						 | 
					0e8ca1a042 | ||
| 
						 | 
					f5f26c9cff | ||
| 
						 | 
					91ac69382d | ||
| 
						 | 
					8cc345fcf5 | ||
| 
						 | 
					96b5042dda | ||
| 
						 | 
					428c687b5a | ||
| 
						 | 
					82bdd1e353 | ||
| 
						 | 
					4bebc5e5fa | ||
| 
						 | 
					be5643cee7 | ||
| 
						 | 
					2ee1c5fa61 | ||
| 
						 | 
					c625d2ee9d | ||
| 
						 | 
					3078f70f90 | ||
| 
						 | 
					7309b20c25 | ||
| 
						 | 
					c16a5ec1cf | ||
| 
						 | 
					f3e1964362 | ||
| 
						 | 
					9b9083180f | ||
| 
						 | 
					7606f79a1e | ||
| 
						 | 
					99c0b82b15 | ||
| 
						 | 
					ca7c1d5e02 | ||
| 
						 | 
					4a770907c1 | ||
| 
						 | 
					049f1556dc | ||
| 
						 | 
					7b20d151ed | ||
| 
						 | 
					8ec0c99ff4 | ||
| 
						 | 
					cf3ee327a0 | ||
| 
						 | 
					3ec3cc248d | ||
| 
						 | 
					7fb3ecc12c | ||
| 
						 | 
					4c9af7267d | ||
| 
						 | 
					db4355ba1e | ||
| 
						 | 
					33150569cd | ||
| 
						 | 
					af2a13ded4 | ||
| 
						 | 
					8b200de35a | ||
| 
						 | 
					57ae203aab | ||
| 
						 | 
					bff75b64be | ||
| 
						 | 
					8899b9da01 | ||
| 
						 | 
					76e816a14f | ||
| 
						 | 
					2750db2a89 | ||
| 
						 | 
					86a913d37a | ||
| 
						 | 
					2857fdbdb8 | ||
| 
						 | 
					69a7d5ff02 | ||
| 
						 | 
					a4f763ac3b | ||
| 
						 | 
					f2afa7aa6c | ||
| 
						 | 
					a5d2555196 | ||
| 
						 | 
					dd5a4ecdf9 | ||
| 
						 | 
					43a1d43f2b | ||
| 
						 | 
					d6d377a447 | ||
| 
						 | 
					ffd95c2ad5 | ||
| 
						 | 
					72be89dfb9 | ||
| 
						 | 
					2feeb57dee | 
							
								
								
									
										14
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -64,12 +64,14 @@ src/meta-dbus-idle-monitor.[ch]
 | 
			
		||||
src/meta-dbus-login1.[ch]
 | 
			
		||||
src/gtk-shell-protocol.c
 | 
			
		||||
src/gtk-shell-server-protocol.h
 | 
			
		||||
src/xdg-shell-protocol.c
 | 
			
		||||
src/xdg-shell-server-protocol.h
 | 
			
		||||
src/pointer-gestures-protocol.c
 | 
			
		||||
src/pointer-gestures-server-protocol.h
 | 
			
		||||
src/xserver-protocol.c
 | 
			
		||||
src/xserver-server-protocol.h
 | 
			
		||||
src/xdg-shell-unstable-v*-protocol.c
 | 
			
		||||
src/xdg-shell-unstable-v*-server-protocol.h
 | 
			
		||||
src/pointer-gestures-unstable-v*-protocol.c
 | 
			
		||||
src/pointer-gestures-unstable-v*-server-protocol.h
 | 
			
		||||
src/relative-pointer-unstable-v*-protocol.c
 | 
			
		||||
src/relative-pointer-unstable-v*-server-protocol.h
 | 
			
		||||
src/pointer-constraints-unstable-v*-protocol.c
 | 
			
		||||
src/pointer-constraints-unstable-v*-server-protocol.h
 | 
			
		||||
src/meta/meta-version.h
 | 
			
		||||
doc/reference/*.args
 | 
			
		||||
doc/reference/*.bak
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,3 +1,64 @@
 | 
			
		||||
3.19.4
 | 
			
		||||
======
 | 
			
		||||
* Fix updating stacking order when setting transient_for [Jonas; #755606]
 | 
			
		||||
* Support screen rotation when supported by the driver [Carlos; #745079]
 | 
			
		||||
* Protect against broken WM_CLASS property implementations [Sebastian; #759658]
 | 
			
		||||
* Handle wl_pointer v5 events on wayland [Carlos; #760637]
 | 
			
		||||
* Implement DND actions on wayland [Carlos; #760805]
 | 
			
		||||
* Misc. bug fixes [Jonas, Rui, Ray, Marek; #754711, #756789, #759297, #758613,
 | 
			
		||||
  #760330, #760476, #759222, #760670]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Jonas Ådahl, Marek Chalupa, Carlos Garnacho, Sebastian Keller, Rui Matos,
 | 
			
		||||
  Florian Müllner, Jasper St. Pierre, Ray Strode
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Aurimas Černius [lt]
 | 
			
		||||
 | 
			
		||||
3.19.3
 | 
			
		||||
======
 | 
			
		||||
* Correct refresh rate units on KMS/Wayland [Daniel; #758653]
 | 
			
		||||
* Fix crash when initial cursor position is not on a monitor [Marek; #756698]
 | 
			
		||||
* Fix crash when more CRTs are enabled than outputs connected [Rui; #751638]
 | 
			
		||||
* Fix touch pointer emulation on wayland [Carlos; #756754]
 | 
			
		||||
* Allow minimizing windows that don't advertise supporting it [Jasper; #758186]
 | 
			
		||||
* Force 2-finger scroll by default if available [Bastien; #759304]
 | 
			
		||||
* Fix crash during XWayland initialization [Marek; #751845]
 | 
			
		||||
* Ensure to send a ConfigureNotify to just mapped windows [Rui; #759492]
 | 
			
		||||
* Misc. bug fixes and cleanups [Carlos, Jonas, Lionel; #758239, #758633,
 | 
			
		||||
  #755503, #759374]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Jonas Ådahl, Marek Chalupa, Carlos Garnacho, Lionel Landwerlin, Rui Matos,
 | 
			
		||||
  Bastien Nocera, Daniel Stone, Jasper St. Pierre
 | 
			
		||||
 | 
			
		||||
3.19.2
 | 
			
		||||
======
 | 
			
		||||
* Fix crash on monitor unplug [Rui; #756796]
 | 
			
		||||
* Exit cleanly on initialization errors [Owen; #757311]
 | 
			
		||||
* Allow to determine backend setting from session type [Ray; #741666]
 | 
			
		||||
* Fix DRM device detection for non-PCI devices [Alban; #754911]
 | 
			
		||||
* Don't force placement of windows without buffer on wayland [Marek; #751887]
 | 
			
		||||
* Fix initialization of bypass compositor hint [Rui; #758544]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Alban Browaeys, Marek Chalupa, Rui Matos, Florian Müllner, Ray Strode,
 | 
			
		||||
  Owen W. Taylor
 | 
			
		||||
 | 
			
		||||
3.19.1
 | 
			
		||||
======
 | 
			
		||||
* wayland: Allow to trigger popups through keyboard/touch [Carlos; #756296]
 | 
			
		||||
* Fix modifiers-only input source switching on Ubuntu [Alberts; #756543]
 | 
			
		||||
* Misc. bug fixes [Jonas, Rui, Giovanni, Florian; #756675, #756660, #746420,
 | 
			
		||||
  #756548, #756796, #757101, #757148]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Jonas Ådahl, Giovanni Campagna, Carlos Garnacho, Rui Matos,
 | 
			
		||||
  Alberts Muktupāvels, Florian Müllner
 | 
			
		||||
 | 
			
		||||
Translations:
 | 
			
		||||
  Daniel Șerbănescu [ro]
 | 
			
		||||
 | 
			
		||||
3.18.1
 | 
			
		||||
======
 | 
			
		||||
* Misc. crash fixes [Jonas, Rui, Carlos, Owen, Florian; #755096, #754979,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
AC_PREREQ(2.62)
 | 
			
		||||
 | 
			
		||||
m4_define([mutter_major_version], [3])
 | 
			
		||||
m4_define([mutter_minor_version], [18])
 | 
			
		||||
m4_define([mutter_micro_version], [1])
 | 
			
		||||
m4_define([mutter_minor_version], [19])
 | 
			
		||||
m4_define([mutter_micro_version], [4])
 | 
			
		||||
 | 
			
		||||
m4_define([mutter_version],
 | 
			
		||||
          [mutter_major_version.mutter_minor_version.mutter_micro_version])
 | 
			
		||||
@@ -46,6 +46,7 @@ IT_PROG_INTLTOOL([0.41])
 | 
			
		||||
AC_PROG_CC
 | 
			
		||||
AC_PROG_CC_C_O
 | 
			
		||||
AC_PROG_INSTALL
 | 
			
		||||
AC_PROG_SED
 | 
			
		||||
AC_HEADER_STDC
 | 
			
		||||
PKG_PROG_PKG_CONFIG([0.21])
 | 
			
		||||
 | 
			
		||||
@@ -58,12 +59,12 @@ CANBERRA_GTK_VERSION=0.26
 | 
			
		||||
CLUTTER_PACKAGE=clutter-1.0
 | 
			
		||||
 | 
			
		||||
MUTTER_PC_MODULES="
 | 
			
		||||
   gtk+-3.0 >= 3.9.11
 | 
			
		||||
   gtk+-3.0 >= 3.19.8
 | 
			
		||||
   gio-unix-2.0 >= 2.35.1
 | 
			
		||||
   pango >= 1.2.0
 | 
			
		||||
   cairo >= 1.10.0
 | 
			
		||||
   gsettings-desktop-schemas >= 3.15.92
 | 
			
		||||
   $CLUTTER_PACKAGE >= 1.23.4
 | 
			
		||||
   gsettings-desktop-schemas >= 3.19.3
 | 
			
		||||
   $CLUTTER_PACKAGE >= 1.25.1
 | 
			
		||||
   cogl-1.0 >= 1.17.1
 | 
			
		||||
   upower-glib >= 0.99.0
 | 
			
		||||
   gnome-desktop-3.0
 | 
			
		||||
@@ -219,6 +220,10 @@ AS_IF([test "$have_wayland" = "yes"], [
 | 
			
		||||
    [AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols])])
 | 
			
		||||
  AC_SUBST([WAYLAND_SCANNER])
 | 
			
		||||
  AC_DEFINE([HAVE_WAYLAND],[1],[Define if you want to enable Wayland support])
 | 
			
		||||
 | 
			
		||||
  PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.1],
 | 
			
		||||
		    [ac_wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`])
 | 
			
		||||
  AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $ac_wayland_protocols_pkgdatadir)
 | 
			
		||||
])
 | 
			
		||||
AM_CONDITIONAL([HAVE_WAYLAND],[test "$have_wayland" = "yes"])
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
desktopfiles_in_files = \
 | 
			
		||||
	mutter.desktop.in \
 | 
			
		||||
	mutter-wayland.desktop.in
 | 
			
		||||
	mutter.desktop.in
 | 
			
		||||
desktopfilesdir = $(datadir)/applications
 | 
			
		||||
desktopfiles_DATA = $(desktopfiles_in_files:.desktop.in=.desktop)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
[Desktop Entry]
 | 
			
		||||
Type=Application
 | 
			
		||||
_Name=Mutter (wayland compositor)
 | 
			
		||||
Exec=mutter --wayland --display-server
 | 
			
		||||
NoDisplay=true
 | 
			
		||||
# name of loadable control center module
 | 
			
		||||
X-GNOME-WMSettingsModule=metacity
 | 
			
		||||
# name we put on the WM spec check window
 | 
			
		||||
X-GNOME-WMName=Mutter
 | 
			
		||||
# back compat only 
 | 
			
		||||
X-GnomeWMSettingsLibrary=metacity
 | 
			
		||||
X-GNOME-Bugzilla-Bugzilla=GNOME
 | 
			
		||||
X-GNOME-Bugzilla-Product=mutter
 | 
			
		||||
X-GNOME-Bugzilla-Component=general
 | 
			
		||||
X-GNOME-Autostart-Phase=WindowManager
 | 
			
		||||
X-GNOME-Provides=windowmanager
 | 
			
		||||
X-GNOME-Autostart-Notify=true
 | 
			
		||||
@@ -1 +1,2 @@
 | 
			
		||||
data/mutter-wayland.desktop.in
 | 
			
		||||
# List of source files that should NOT be translated.
 | 
			
		||||
# Please keep this file sorted alphabetically.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								po/lt.po
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								po/lt.po
									
									
									
									
									
								
							@@ -13,8 +13,8 @@ msgstr ""
 | 
			
		||||
"Project-Id-Version: lt\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
 | 
			
		||||
"product=mutter&keywords=I18N+L10N&component=general\n"
 | 
			
		||||
"POT-Creation-Date: 2015-02-28 11:14+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2015-02-28 21:34+0200\n"
 | 
			
		||||
"POT-Creation-Date: 2016-01-05 13:43+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2016-01-05 18:04+0200\n"
 | 
			
		||||
"Last-Translator: Aurimas Černius <aurisc4@gmail.com>\n"
 | 
			
		||||
"Language-Team: Lietuvių <gnome-lt@lists.akl.lt>\n"
 | 
			
		||||
"Language: lt\n"
 | 
			
		||||
@@ -23,7 +23,7 @@ msgstr ""
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
 | 
			
		||||
"%100<10 || n%100>=20) ? 1 : 2);\n"
 | 
			
		||||
"X-Generator: Gtranslator 2.91.6\n"
 | 
			
		||||
"X-Generator: Poedit 1.8.6\n"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:1
 | 
			
		||||
msgid "Navigation"
 | 
			
		||||
@@ -31,39 +31,39 @@ msgstr "Navigacija"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:2
 | 
			
		||||
msgid "Move window to workspace 1"
 | 
			
		||||
msgstr "Perkelti langą į darbalaukį Nr.1"
 | 
			
		||||
msgstr "Perkelti langą į darbo sritį Nr.1"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:3
 | 
			
		||||
msgid "Move window to workspace 2"
 | 
			
		||||
msgstr "Perkelti langą į darbalaukį Nr.2"
 | 
			
		||||
msgstr "Perkelti langą į darbo sritį Nr.2"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:4
 | 
			
		||||
msgid "Move window to workspace 3"
 | 
			
		||||
msgstr "Perkelti langą į darbalaukį Nr.3"
 | 
			
		||||
msgstr "Perkelti langą į darbo sritį Nr.3"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:5
 | 
			
		||||
msgid "Move window to workspace 4"
 | 
			
		||||
msgstr "Perkelti langą į darbalaukį Nr.4"
 | 
			
		||||
msgstr "Perkelti langą į darbo sritį Nr.4"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:6
 | 
			
		||||
msgid "Move window to last workspace"
 | 
			
		||||
msgstr "Perkelti langą į pastarąjį darbalaukį"
 | 
			
		||||
msgstr "Perkelti langą į pastarąją darbo sritį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:7
 | 
			
		||||
msgid "Move window one workspace to the left"
 | 
			
		||||
msgstr "Perkelti langą į kairiau esantį darbalaukį"
 | 
			
		||||
msgstr "Perkelti langą į kairiau esančią darbo sritį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:8
 | 
			
		||||
msgid "Move window one workspace to the right"
 | 
			
		||||
msgstr "Perkelti langą į dešiniau esantį darbalaukį"
 | 
			
		||||
msgstr "Perkelti langą į dešiniau esančią darbo sritį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:9
 | 
			
		||||
msgid "Move window one workspace up"
 | 
			
		||||
msgstr "Perkelti langą į aukščiau esantį darbalaukį"
 | 
			
		||||
msgstr "Perkelti langą į aukščiau esančią darbo sritį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:10
 | 
			
		||||
msgid "Move window one workspace down"
 | 
			
		||||
msgstr "Perkelti langą į žemiau esantį darbalaukį"
 | 
			
		||||
msgstr "Perkelti langą į žemiau esančią darbo sritį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:11
 | 
			
		||||
msgid "Move window one monitor to the left"
 | 
			
		||||
@@ -143,39 +143,39 @@ msgstr "Paslėpti visus įprastinius langus"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:30
 | 
			
		||||
msgid "Switch to workspace 1"
 | 
			
		||||
msgstr "Persijungti į darbalaukį Nr.1"
 | 
			
		||||
msgstr "Persijungti į darbo sritį Nr.1"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:31
 | 
			
		||||
msgid "Switch to workspace 2"
 | 
			
		||||
msgstr "Persijungti į darbalaukį Nr.2"
 | 
			
		||||
msgstr "Persijungti į darbo sritį Nr.2"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:32
 | 
			
		||||
msgid "Switch to workspace 3"
 | 
			
		||||
msgstr "Persijungti į darbalaukį Nr.3"
 | 
			
		||||
msgstr "Persijungti į darbo sritį Nr.3"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:33
 | 
			
		||||
msgid "Switch to workspace 4"
 | 
			
		||||
msgstr "Persijungti į darbalaukį Nr.4"
 | 
			
		||||
msgstr "Persijungti į darbo sritį Nr.4"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:34
 | 
			
		||||
msgid "Switch to last workspace"
 | 
			
		||||
msgstr "Persijungti į pastarąjį darbalaukį"
 | 
			
		||||
msgstr "Persijungti į pastarąją darbo sritį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:35
 | 
			
		||||
msgid "Move to workspace left"
 | 
			
		||||
msgstr "Perkelti į darbalaukį kairėje"
 | 
			
		||||
msgstr "Perkelti į darbo sritį kairėje"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:36
 | 
			
		||||
msgid "Move to workspace right"
 | 
			
		||||
msgstr "Perkelti į darbalaukį dešinėje"
 | 
			
		||||
msgstr "Perkelti į darbo sritį dešinėje"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:37
 | 
			
		||||
msgid "Move to workspace above"
 | 
			
		||||
msgstr "Perkelti į darbalaukį viršuje"
 | 
			
		||||
msgstr "Perkelti į darbo sritį viršuje"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-navigation.xml.in.h:38
 | 
			
		||||
msgid "Move to workspace below"
 | 
			
		||||
msgstr "Perkelti į darbalaukį apačioje"
 | 
			
		||||
msgstr "Perkelti į darbo sritį apačioje"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-system.xml.in.h:1
 | 
			
		||||
msgid "System"
 | 
			
		||||
@@ -235,7 +235,7 @@ msgstr "Keisti lango dydį"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-windows.xml.in.h:12
 | 
			
		||||
msgid "Toggle window on all workspaces or one"
 | 
			
		||||
msgstr "Perjungti lango buvimo visuose darbalaukiuose būseną"
 | 
			
		||||
msgstr "Perjungti lango buvimo visose darbo srityse būseną"
 | 
			
		||||
 | 
			
		||||
#: ../data/50-mutter-windows.xml.in.h:13
 | 
			
		||||
msgid "Raise window if covered, otherwise lower it"
 | 
			
		||||
@@ -272,7 +272,7 @@ msgstr "Mutter"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:1
 | 
			
		||||
msgid "Modifier to use for extended window management operations"
 | 
			
		||||
msgstr "Klavišas, naudojamas kartu su specialiais lango valdymo veiksmais"
 | 
			
		||||
msgstr "Klavišas, naudojamas kartu su specialiomis lango tvarkymo operacijomis"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:2
 | 
			
		||||
msgid ""
 | 
			
		||||
@@ -315,7 +315,7 @@ msgstr ""
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:7
 | 
			
		||||
msgid "Workspaces are managed dynamically"
 | 
			
		||||
msgstr "Darbalaukiai valdomi dinamiškai"
 | 
			
		||||
msgstr "Darbo sritys tvarkomos dinamiškai"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:8
 | 
			
		||||
msgid ""
 | 
			
		||||
@@ -323,21 +323,21 @@ msgid ""
 | 
			
		||||
"static number of workspaces (determined by the num-workspaces key in org."
 | 
			
		||||
"gnome.desktop.wm.preferences)."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Nusako, ar darbastaliai yra valdomi dinamiškai, ar yra pastovus darbalaukių "
 | 
			
		||||
"skaičius (nusakomas raktu num-workspaces schemoje org.gnome.desktop.wm."
 | 
			
		||||
"preferences)."
 | 
			
		||||
"Nusako, ar darbo sritys yra tvarkomos dinamiškai, ar yra pastovus darbo "
 | 
			
		||||
"sričių skaičius (nusakomas raktu num-workspaces schemoje org.gnome.desktop."
 | 
			
		||||
"wm.preferences)."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:9
 | 
			
		||||
msgid "Workspaces only on primary"
 | 
			
		||||
msgstr "Darbalaukiai tik pagrindiniame"
 | 
			
		||||
msgstr "Darbo sritys tik pagrindiniame"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:10
 | 
			
		||||
msgid ""
 | 
			
		||||
"Determines whether workspace switching should happen for windows on all "
 | 
			
		||||
"monitors or only for windows on the primary monitor."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Nusako, ar darbalaukių perjungimas turi įvykti langams viusose monitoriuose, "
 | 
			
		||||
"ar tik langams pagrindiniame monitoriuje."
 | 
			
		||||
"Nusako, ar darbo sričių perjungimas turi įvykti langams visuose "
 | 
			
		||||
"monitoriuose, ar tik langams pagrindiniame monitoriuje."
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:11
 | 
			
		||||
msgid "No tab popup"
 | 
			
		||||
@@ -438,46 +438,41 @@ msgid "Switch to VT 7"
 | 
			
		||||
msgstr "Persijungti į VT 7"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:8
 | 
			
		||||
#| msgid "Switch to VT 1"
 | 
			
		||||
msgid "Switch to VT 8"
 | 
			
		||||
msgstr "Persijungti į VT 8"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:9
 | 
			
		||||
#| msgid "Switch to VT 1"
 | 
			
		||||
msgid "Switch to VT 9"
 | 
			
		||||
msgstr "Persijungti į VT 9"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:10
 | 
			
		||||
#| msgid "Switch to VT 1"
 | 
			
		||||
msgid "Switch to VT 10"
 | 
			
		||||
msgstr "Persijungti į VT 10"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:11
 | 
			
		||||
#| msgid "Switch to VT 1"
 | 
			
		||||
msgid "Switch to VT 11"
 | 
			
		||||
msgstr "Persijungti į VT 11"
 | 
			
		||||
 | 
			
		||||
#: ../data/org.gnome.mutter.wayland.gschema.xml.in.h:12
 | 
			
		||||
#| msgid "Switch to VT 1"
 | 
			
		||||
msgid "Switch to VT 12"
 | 
			
		||||
msgstr "Persijungti į VT 12"
 | 
			
		||||
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:364
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:518
 | 
			
		||||
msgid "Built-in display"
 | 
			
		||||
msgstr "Integruotas vaizduoklis"
 | 
			
		||||
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:391
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:544
 | 
			
		||||
msgid "Unknown"
 | 
			
		||||
msgstr "Nežinomas"
 | 
			
		||||
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:393
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:546
 | 
			
		||||
msgid "Unknown Display"
 | 
			
		||||
msgstr "Nežinomas vaizduoklis"
 | 
			
		||||
 | 
			
		||||
#. TRANSLATORS: this is a monitor vendor name, followed by a
 | 
			
		||||
#. * size in inches, like 'Dell 15"'
 | 
			
		||||
#.
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:401
 | 
			
		||||
#: ../src/backends/meta-monitor-manager.c:554
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "%s %s"
 | 
			
		||||
msgstr "%s %s"
 | 
			
		||||
@@ -489,7 +484,7 @@ msgstr "%s %s"
 | 
			
		||||
msgid ""
 | 
			
		||||
"Another compositing manager is already running on screen %i on display \"%s"
 | 
			
		||||
"\"."
 | 
			
		||||
msgstr "Kita kompozicijos valdyklė jau veikia ekrane %i vaizduoklyje „%s“."
 | 
			
		||||
msgstr "Kita kompozicijos tvarkytuvė jau veikia ekrane %i vaizduoklyje „%s“."
 | 
			
		||||
 | 
			
		||||
#: ../src/core/bell.c:185
 | 
			
		||||
msgid "Bell event"
 | 
			
		||||
@@ -518,40 +513,40 @@ msgstr "_Laukti"
 | 
			
		||||
msgid "_Force Quit"
 | 
			
		||||
msgstr "_Priverstinai išeiti"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/display.c:562
 | 
			
		||||
#: ../src/core/display.c:563
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Failed to open X Window System display '%s'\n"
 | 
			
		||||
msgstr "Nepavyko atverti X Window sistemos ekrano „%s“\n"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:176
 | 
			
		||||
#: ../src/core/main.c:180
 | 
			
		||||
msgid "Disable connection to session manager"
 | 
			
		||||
msgstr "Išjungti susijungimą su sesijos valdykle"
 | 
			
		||||
msgstr "Išjungti susijungimą su sesijos tvarkytuve"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:182
 | 
			
		||||
#: ../src/core/main.c:186
 | 
			
		||||
msgid "Replace the running window manager"
 | 
			
		||||
msgstr "Pakeisti veikiančią langų valdyklę"
 | 
			
		||||
msgstr "Pakeisti veikiančią langų tvarkytuvę"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:188
 | 
			
		||||
#: ../src/core/main.c:192
 | 
			
		||||
msgid "Specify session management ID"
 | 
			
		||||
msgstr "Nurodyti sesijos valdymo ID"
 | 
			
		||||
msgstr "Nurodyti sesijos tvarkymo ID"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:193
 | 
			
		||||
#: ../src/core/main.c:197
 | 
			
		||||
msgid "X Display to use"
 | 
			
		||||
msgstr "Naudotinas X ekranas"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:199
 | 
			
		||||
#: ../src/core/main.c:203
 | 
			
		||||
msgid "Initialize session from savefile"
 | 
			
		||||
msgstr "Inicializuoti sesiją iš išsaugojimo failo"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:205
 | 
			
		||||
#: ../src/core/main.c:209
 | 
			
		||||
msgid "Make X calls synchronous"
 | 
			
		||||
msgstr "Sinchronizuoti X iškvietimus"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:212
 | 
			
		||||
#: ../src/core/main.c:216
 | 
			
		||||
msgid "Run as a wayland compositor"
 | 
			
		||||
msgstr "Vykdyti kaip wayland kompozitorių"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/main.c:220
 | 
			
		||||
#: ../src/core/main.c:224
 | 
			
		||||
msgid "Run as a full display server, rather than nested"
 | 
			
		||||
msgstr "Vykdyti kaip visą vaizduoklio serverį, o ne vidinį"
 | 
			
		||||
 | 
			
		||||
@@ -580,24 +575,21 @@ msgstr "Parodyti versiją"
 | 
			
		||||
msgid "Mutter plugin to use"
 | 
			
		||||
msgstr "Naudojamas Mutter įskiepis"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/prefs.c:2004
 | 
			
		||||
#: ../src/core/prefs.c:1997
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Workspace %d"
 | 
			
		||||
msgstr "Darbalaukis %d"
 | 
			
		||||
msgstr "Darbo sritis %d"
 | 
			
		||||
 | 
			
		||||
#: ../src/core/screen.c:525
 | 
			
		||||
#: ../src/core/screen.c:526
 | 
			
		||||
#, c-format
 | 
			
		||||
#| msgid ""
 | 
			
		||||
#| "Screen %d on display \"%s\" already has a window manager; try using the --"
 | 
			
		||||
#| "replace option to replace the current window manager.\n"
 | 
			
		||||
msgid ""
 | 
			
		||||
"Display \"%s\" already has a window manager; try using the --replace option "
 | 
			
		||||
"to replace the current window manager."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Vaizduoklis „%s“ jau turi langų valdyklę; pabandykite pakeisti esamą langų "
 | 
			
		||||
"valdyklę naudodami parametrą --replace."
 | 
			
		||||
"Vaizduoklis „%s“ jau turi langų tvarkytuvę; pabandykite pakeisti esamą langų "
 | 
			
		||||
"tvarkytuvę, naudodami parametrą --replace."
 | 
			
		||||
 | 
			
		||||
#: ../src/core/screen.c:607
 | 
			
		||||
#: ../src/core/screen.c:608
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Screen %d on display '%s' is invalid\n"
 | 
			
		||||
msgstr "Ekranas %d vaizduoklyje „%s“ netinkamas\n"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ dist_stacking_DATA =				\
 | 
			
		||||
	tests/stacking/basic-wayland.metatest	\
 | 
			
		||||
	tests/stacking/minimized.metatest   	\
 | 
			
		||||
	tests/stacking/mixed-windows.metatest   \
 | 
			
		||||
	tests/stacking/set-parent.metatest	\
 | 
			
		||||
	tests/stacking/override-redirect.metatest
 | 
			
		||||
 | 
			
		||||
mutter-all.test: tests/mutter-all.test.in
 | 
			
		||||
 
 | 
			
		||||
@@ -45,19 +45,21 @@ mutter_built_sources = \
 | 
			
		||||
 | 
			
		||||
if HAVE_WAYLAND
 | 
			
		||||
mutter_built_sources += \
 | 
			
		||||
	pointer-gestures-protocol.c		\
 | 
			
		||||
	pointer-gestures-server-protocol.h	\
 | 
			
		||||
	pointer-gestures-unstable-v1-protocol.c				\
 | 
			
		||||
	pointer-gestures-unstable-v1-server-protocol.h			\
 | 
			
		||||
	gtk-shell-protocol.c			\
 | 
			
		||||
	gtk-shell-server-protocol.h		\
 | 
			
		||||
	xdg-shell-protocol.c			\
 | 
			
		||||
	xdg-shell-server-protocol.h		\
 | 
			
		||||
	xdg-shell-unstable-v5-protocol.c				\
 | 
			
		||||
	xdg-shell-unstable-v5-server-protocol.h				\
 | 
			
		||||
	relative-pointer-unstable-v1-protocol.c				\
 | 
			
		||||
	relative-pointer-unstable-v1-server-protocol.h			\
 | 
			
		||||
	pointer-constraints-unstable-v1-protocol.c			\
 | 
			
		||||
	pointer-constraints-unstable-v1-server-protocol.h		\
 | 
			
		||||
	$(NULL)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
wayland_protocols =				\
 | 
			
		||||
	wayland/protocol/pointer-gestures.xml	\
 | 
			
		||||
	wayland/protocol/gtk-shell.xml		\
 | 
			
		||||
	wayland/protocol/xdg-shell.xml		\
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
libmutter_la_SOURCES =				\
 | 
			
		||||
@@ -86,6 +88,8 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	backends/meta-monitor-manager-private.h	\
 | 
			
		||||
	backends/meta-monitor-manager-dummy.c	\
 | 
			
		||||
	backends/meta-monitor-manager-dummy.h	\
 | 
			
		||||
	backends/meta-pointer-constraint.c	\
 | 
			
		||||
	backends/meta-pointer-constraint.h	\
 | 
			
		||||
	backends/meta-stage.h			\
 | 
			
		||||
	backends/meta-stage.c			\
 | 
			
		||||
	backends/edid-parse.c			\
 | 
			
		||||
@@ -112,6 +116,8 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	core/boxes.c				\
 | 
			
		||||
	core/boxes-private.h			\
 | 
			
		||||
	meta/boxes.h				\
 | 
			
		||||
	core/meta-border.c			\
 | 
			
		||||
	core/meta-border.h			\
 | 
			
		||||
	compositor/clutter-utils.c		\
 | 
			
		||||
	compositor/clutter-utils.h		\
 | 
			
		||||
	compositor/cogl-utils.c			\
 | 
			
		||||
@@ -192,6 +198,8 @@ libmutter_la_SOURCES =				\
 | 
			
		||||
	core/screen.c				\
 | 
			
		||||
	core/screen-private.h			\
 | 
			
		||||
	meta/screen.h				\
 | 
			
		||||
	core/startup-notification.c		\
 | 
			
		||||
	core/startup-notification-private.h	\
 | 
			
		||||
	meta/types.h				\
 | 
			
		||||
	core/restart.c				\
 | 
			
		||||
	core/stack.c				\
 | 
			
		||||
@@ -266,6 +274,12 @@ libmutter_la_SOURCES +=				\
 | 
			
		||||
	wayland/meta-wayland-keyboard.h		\
 | 
			
		||||
	wayland/meta-wayland-pointer.c		\
 | 
			
		||||
	wayland/meta-wayland-pointer.h		\
 | 
			
		||||
	wayland/meta-wayland-pointer-constraints.c	\
 | 
			
		||||
	wayland/meta-wayland-pointer-constraints.h	\
 | 
			
		||||
	wayland/meta-pointer-lock-wayland.c		\
 | 
			
		||||
	wayland/meta-pointer-lock-wayland.h		\
 | 
			
		||||
	wayland/meta-pointer-confinement-wayland.c	\
 | 
			
		||||
	wayland/meta-pointer-confinement-wayland.h	\
 | 
			
		||||
	wayland/meta-wayland-popup.c		\
 | 
			
		||||
	wayland/meta-wayland-popup.h		\
 | 
			
		||||
	wayland/meta-wayland-seat.c		\
 | 
			
		||||
@@ -481,6 +495,20 @@ $(dbus_login1_built_sources) : Makefile.am org.freedesktop.login1.xml
 | 
			
		||||
		--generate-c-code meta-dbus-login1					\
 | 
			
		||||
		$(srcdir)/org.freedesktop.login1.xml
 | 
			
		||||
 | 
			
		||||
.SECONDEXPANSION:
 | 
			
		||||
 | 
			
		||||
define protostability
 | 
			
		||||
$(shell echo $1 | sed 's/.*\(\<unstable\>\|\<stable\>\).*/\1/')
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
define protoname
 | 
			
		||||
$(shell echo $1 | sed 's/\([a-z\-]\+\)-[a-z]\+-v[0-9]\+/\1/')
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
%-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/$$(call protostability,$$*)/$$(call protoname,$$*)/$$*.xml
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 | 
			
		||||
%-server-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/$$(call protostability,$$*)/$$(call protoname,$$*)/$$*.xml
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
 | 
			
		||||
%-protocol.c : $(srcdir)/wayland/protocol/%.xml
 | 
			
		||||
	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
 | 
			
		||||
%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
#include <meta/meta-idle-monitor.h>
 | 
			
		||||
#include "meta-cursor-renderer.h"
 | 
			
		||||
#include "meta-monitor-manager-private.h"
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_XKB_RULES_FILE "evdev"
 | 
			
		||||
#define DEFAULT_XKB_MODEL "pc105+inet"
 | 
			
		||||
@@ -51,6 +52,8 @@ struct _MetaBackend
 | 
			
		||||
 | 
			
		||||
  GHashTable *device_monitors;
 | 
			
		||||
  gint current_device_id;
 | 
			
		||||
 | 
			
		||||
  MetaPointerConstraint *client_pointer_constraint;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaBackendClass
 | 
			
		||||
@@ -87,6 +90,13 @@ struct _MetaBackendClass
 | 
			
		||||
 | 
			
		||||
  void (* update_screen_size) (MetaBackend *backend, int width, int height);
 | 
			
		||||
  void (* select_stage_events) (MetaBackend *backend);
 | 
			
		||||
 | 
			
		||||
  gboolean (* get_relative_motion_deltas) (MetaBackend *backend,
 | 
			
		||||
                                           const        ClutterEvent *event,
 | 
			
		||||
                                           double       *dx,
 | 
			
		||||
                                           double       *dy,
 | 
			
		||||
                                           double       *dx_unaccel,
 | 
			
		||||
                                           double       *dy_unaccel);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
 | 
			
		||||
@@ -110,4 +120,14 @@ struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
 | 
			
		||||
void meta_backend_update_last_device (MetaBackend *backend,
 | 
			
		||||
                                      int          device_id);
 | 
			
		||||
 | 
			
		||||
gboolean meta_backend_get_relative_motion_deltas (MetaBackend *backend,
 | 
			
		||||
                                                  const        ClutterEvent *event,
 | 
			
		||||
                                                  double       *dx,
 | 
			
		||||
                                                  double       *dy,
 | 
			
		||||
                                                  double       *dx_unaccel,
 | 
			
		||||
                                                  double       *dy_unaccel);
 | 
			
		||||
 | 
			
		||||
void meta_backend_set_client_pointer_constraint (MetaBackend *backend,
 | 
			
		||||
                                                 MetaPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
#endif /* META_BACKEND_PRIVATE_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,8 @@
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/meta-backend.h>
 | 
			
		||||
#include "meta-backend-private.h"
 | 
			
		||||
#include "meta-input-settings-private.h"
 | 
			
		||||
@@ -351,6 +353,17 @@ meta_backend_real_select_stage_events (MetaBackend *backend)
 | 
			
		||||
  /* Do nothing */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_backend_real_get_relative_motion_deltas (MetaBackend *backend,
 | 
			
		||||
                                             const         ClutterEvent *event,
 | 
			
		||||
                                             double        *dx,
 | 
			
		||||
                                             double        *dy,
 | 
			
		||||
                                             double        *dx_unaccel,
 | 
			
		||||
                                             double        *dy_unaccel)
 | 
			
		||||
{
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_class_init (MetaBackendClass *klass)
 | 
			
		||||
{
 | 
			
		||||
@@ -364,6 +377,7 @@ meta_backend_class_init (MetaBackendClass *klass)
 | 
			
		||||
  klass->ungrab_device = meta_backend_real_ungrab_device;
 | 
			
		||||
  klass->update_screen_size = meta_backend_real_update_screen_size;
 | 
			
		||||
  klass->select_stage_events = meta_backend_real_select_stage_events;
 | 
			
		||||
  klass->get_relative_motion_deltas = meta_backend_real_get_relative_motion_deltas;
 | 
			
		||||
 | 
			
		||||
  g_signal_new ("keymap-changed",
 | 
			
		||||
                G_TYPE_FROM_CLASS (object_class),
 | 
			
		||||
@@ -542,6 +556,32 @@ meta_backend_update_last_device (MetaBackend *backend,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_backend_get_relative_motion_deltas (MetaBackend *backend,
 | 
			
		||||
                                         const        ClutterEvent *event,
 | 
			
		||||
                                         double       *dx,
 | 
			
		||||
                                         double       *dy,
 | 
			
		||||
                                         double       *dx_unaccel,
 | 
			
		||||
                                         double       *dy_unaccel)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendClass *klass = META_BACKEND_GET_CLASS (backend);
 | 
			
		||||
  return klass->get_relative_motion_deltas (backend,
 | 
			
		||||
                                            event,
 | 
			
		||||
                                            dx, dy,
 | 
			
		||||
                                            dx_unaccel, dy_unaccel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_backend_set_client_pointer_constraint (MetaBackend           *backend,
 | 
			
		||||
                                            MetaPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  g_assert (!constraint || (constraint && !backend->client_pointer_constraint));
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&backend->client_pointer_constraint);
 | 
			
		||||
  if (constraint)
 | 
			
		||||
    backend->client_pointer_constraint = g_object_ref (constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GType
 | 
			
		||||
get_backend_type (void)
 | 
			
		||||
{
 | 
			
		||||
@@ -626,7 +666,10 @@ meta_clutter_init (void)
 | 
			
		||||
  meta_create_backend ();
 | 
			
		||||
 | 
			
		||||
  if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
 | 
			
		||||
    g_error ("Unable to initialize Clutter.\n");
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Unable to initialize Clutter.\n");
 | 
			
		||||
      exit (1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,8 @@
 | 
			
		||||
#ifndef META_BARRIER_PRIVATE_H
 | 
			
		||||
#define META_BARRIER_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include "core/meta-border.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_BARRIER_IMPL            (meta_barrier_impl_get_type ())
 | 
			
		||||
@@ -67,14 +69,7 @@ G_END_DECLS
 | 
			
		||||
struct _MetaBarrierPrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
 | 
			
		||||
  int x1;
 | 
			
		||||
  int y1;
 | 
			
		||||
  int x2;
 | 
			
		||||
  int y2;
 | 
			
		||||
 | 
			
		||||
  MetaBarrierDirection directions;
 | 
			
		||||
 | 
			
		||||
  MetaBorder border;
 | 
			
		||||
  MetaBarrierImpl *impl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -61,19 +61,20 @@ meta_barrier_get_property (GObject    *object,
 | 
			
		||||
      g_value_set_object (value, priv->display);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_X1:
 | 
			
		||||
      g_value_set_int (value, priv->x1);
 | 
			
		||||
      g_value_set_int (value, priv->border.line.a.x);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_Y1:
 | 
			
		||||
      g_value_set_int (value, priv->y1);
 | 
			
		||||
      g_value_set_int (value, priv->border.line.a.y);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_X2:
 | 
			
		||||
      g_value_set_int (value, priv->x2);
 | 
			
		||||
      g_value_set_int (value, priv->border.line.b.x);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_Y2:
 | 
			
		||||
      g_value_set_int (value, priv->y2);
 | 
			
		||||
      g_value_set_int (value, priv->border.line.b.y);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_DIRECTIONS:
 | 
			
		||||
      g_value_set_flags (value, priv->directions);
 | 
			
		||||
      g_value_set_flags (value,
 | 
			
		||||
                         meta_border_get_allows_directions (&priv->border));
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
@@ -95,19 +96,20 @@ meta_barrier_set_property (GObject      *object,
 | 
			
		||||
      priv->display = g_value_get_object (value);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_X1:
 | 
			
		||||
      priv->x1 = g_value_get_int (value);
 | 
			
		||||
      priv->border.line.a.x = g_value_get_int (value);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_Y1:
 | 
			
		||||
      priv->y1 = g_value_get_int (value);
 | 
			
		||||
      priv->border.line.a.y = g_value_get_int (value);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_X2:
 | 
			
		||||
      priv->x2 = g_value_get_int (value);
 | 
			
		||||
      priv->border.line.b.x = g_value_get_int (value);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_Y2:
 | 
			
		||||
      priv->y2 = g_value_get_int (value);
 | 
			
		||||
      priv->border.line.b.y = g_value_get_int (value);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_DIRECTIONS:
 | 
			
		||||
      priv->directions = g_value_get_flags (value);
 | 
			
		||||
      meta_border_set_allows_directions (&priv->border,
 | 
			
		||||
                                         g_value_get_flags (value));
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
@@ -166,7 +168,8 @@ meta_barrier_constructed (GObject *object)
 | 
			
		||||
  MetaBarrier *barrier = META_BARRIER (object);
 | 
			
		||||
  MetaBarrierPrivate *priv = barrier->priv;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (priv->x1 == priv->x2 || priv->y1 == priv->y2);
 | 
			
		||||
  g_return_if_fail (priv->border.line.a.x == priv->border.line.b.x ||
 | 
			
		||||
                    priv->border.line.a.y == priv->border.line.b.y);
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_NATIVE_BACKEND)
 | 
			
		||||
  if (META_IS_BACKEND_NATIVE (meta_get_backend ()))
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,8 @@
 | 
			
		||||
#include "meta-cursor-renderer.h"
 | 
			
		||||
 | 
			
		||||
#include <meta/meta-backend.h>
 | 
			
		||||
#include <backends/meta-backend-private.h>
 | 
			
		||||
#include <backends/meta-monitor-manager-private.h>
 | 
			
		||||
#include <meta/util.h>
 | 
			
		||||
 | 
			
		||||
#include <cogl/cogl.h>
 | 
			
		||||
@@ -116,6 +118,14 @@ meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_cursor_in_monitors_area (int x, int y)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (meta_get_backend ());
 | 
			
		||||
  return meta_monitor_manager_get_monitor_at_point (monitor_manager,
 | 
			
		||||
                                                    (gfloat) x, (gfloat) y) >= 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_cursor (MetaCursorRenderer *renderer,
 | 
			
		||||
               MetaCursorSprite   *cursor_sprite)
 | 
			
		||||
@@ -124,6 +134,11 @@ update_cursor (MetaCursorRenderer *renderer,
 | 
			
		||||
  gboolean handled_by_backend;
 | 
			
		||||
  gboolean should_redraw = FALSE;
 | 
			
		||||
 | 
			
		||||
  /* do not render cursor if it is not on any monitor. Such situation
 | 
			
		||||
   * can occur e. g. after monitor hot-plug */
 | 
			
		||||
  if (!is_cursor_in_monitors_area (priv->current_x, priv->current_y))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (cursor_sprite)
 | 
			
		||||
    meta_cursor_sprite_prepare_at (cursor_sprite,
 | 
			
		||||
                                   priv->current_x,
 | 
			
		||||
 
 | 
			
		||||
@@ -361,12 +361,12 @@ get_pointer_position_gdk (int         *x,
 | 
			
		||||
                          int         *y,
 | 
			
		||||
                          int         *mods)
 | 
			
		||||
{
 | 
			
		||||
  GdkDeviceManager *gmanager;
 | 
			
		||||
  GdkSeat *gseat;
 | 
			
		||||
  GdkDevice *gdevice;
 | 
			
		||||
  GdkScreen *gscreen;
 | 
			
		||||
 | 
			
		||||
  gmanager = gdk_display_get_device_manager (gdk_display_get_default ());
 | 
			
		||||
  gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);
 | 
			
		||||
  gseat = gdk_display_get_default_seat (gdk_display_get_default ());
 | 
			
		||||
  gdevice = gdk_seat_get_pointer (gseat);
 | 
			
		||||
 | 
			
		||||
  gdk_device_get_position (gdevice, &gscreen, x, y);
 | 
			
		||||
  if (mods)
 | 
			
		||||
 
 | 
			
		||||
@@ -63,9 +63,9 @@ struct _MetaInputSettingsClass
 | 
			
		||||
  void (* set_invert_scroll) (MetaInputSettings  *settings,
 | 
			
		||||
                              ClutterInputDevice *device,
 | 
			
		||||
                              gboolean            inverted);
 | 
			
		||||
  void (* set_scroll_method) (MetaInputSettings            *settings,
 | 
			
		||||
                              ClutterInputDevice           *device,
 | 
			
		||||
                              GDesktopTouchpadScrollMethod  mode);
 | 
			
		||||
  void (* set_edge_scroll)   (MetaInputSettings  *settings,
 | 
			
		||||
                              ClutterInputDevice *device,
 | 
			
		||||
                              gboolean            enabled);
 | 
			
		||||
  void (* set_scroll_button) (MetaInputSettings  *settings,
 | 
			
		||||
                              ClutterInputDevice *device,
 | 
			
		||||
                              guint               button);
 | 
			
		||||
 
 | 
			
		||||
@@ -395,11 +395,11 @@ update_touchpad_tap_enabled (MetaInputSettings  *input_settings,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_touchpad_scroll_method (MetaInputSettings *input_settings,
 | 
			
		||||
                               ClutterInputDevice *device)
 | 
			
		||||
update_touchpad_edge_scroll (MetaInputSettings *input_settings,
 | 
			
		||||
                             ClutterInputDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  MetaInputSettingsClass *input_settings_class;
 | 
			
		||||
  GDesktopTouchpadScrollMethod method;
 | 
			
		||||
  gboolean edge_scroll_enabled;
 | 
			
		||||
  MetaInputSettingsPrivate *priv;
 | 
			
		||||
 | 
			
		||||
  if (device &&
 | 
			
		||||
@@ -408,19 +408,19 @@ update_touchpad_scroll_method (MetaInputSettings *input_settings,
 | 
			
		||||
 | 
			
		||||
  priv = meta_input_settings_get_instance_private (input_settings);
 | 
			
		||||
  input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
 | 
			
		||||
  method = g_settings_get_enum (priv->touchpad_settings, "scroll-method");
 | 
			
		||||
  edge_scroll_enabled = g_settings_get_boolean (priv->touchpad_settings, "edge-scrolling-enabled");
 | 
			
		||||
 | 
			
		||||
  if (device)
 | 
			
		||||
    {
 | 
			
		||||
      settings_device_set_uint_setting (input_settings, device,
 | 
			
		||||
                                        input_settings_class->set_scroll_method,
 | 
			
		||||
                                        method);
 | 
			
		||||
      settings_device_set_bool_setting (input_settings, device,
 | 
			
		||||
                                        input_settings_class->set_edge_scroll,
 | 
			
		||||
                                        edge_scroll_enabled);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      settings_set_uint_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
 | 
			
		||||
                                 (ConfigUintFunc) input_settings_class->set_scroll_method,
 | 
			
		||||
                                 method);
 | 
			
		||||
      settings_set_bool_setting (input_settings, CLUTTER_TOUCHPAD_DEVICE,
 | 
			
		||||
                                 (ConfigBoolFunc) input_settings_class->set_edge_scroll,
 | 
			
		||||
                                 edge_scroll_enabled);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -429,7 +429,7 @@ update_touchpad_click_method (MetaInputSettings *input_settings,
 | 
			
		||||
                              ClutterInputDevice *device)
 | 
			
		||||
{
 | 
			
		||||
  MetaInputSettingsClass *input_settings_class;
 | 
			
		||||
  GDesktopTouchpadScrollMethod method;
 | 
			
		||||
  GDesktopTouchpadClickMethod method;
 | 
			
		||||
  MetaInputSettingsPrivate *priv;
 | 
			
		||||
 | 
			
		||||
  if (device &&
 | 
			
		||||
@@ -645,8 +645,8 @@ meta_input_settings_changed_cb (GSettings  *settings,
 | 
			
		||||
        update_touchpad_tap_enabled (input_settings, NULL);
 | 
			
		||||
      else if (strcmp (key, "send-events") == 0)
 | 
			
		||||
        update_touchpad_send_events (input_settings, NULL);
 | 
			
		||||
      else if (strcmp (key, "scroll-method") == 0)
 | 
			
		||||
        update_touchpad_scroll_method (input_settings, NULL);
 | 
			
		||||
      else if (strcmp (key, "edge-scrolling-enabled") == 0)
 | 
			
		||||
        update_touchpad_edge_scroll (input_settings, NULL);
 | 
			
		||||
      else if (strcmp (key, "click-method") == 0)
 | 
			
		||||
        update_touchpad_click_method (input_settings, NULL);
 | 
			
		||||
    }
 | 
			
		||||
@@ -771,7 +771,7 @@ apply_device_settings (MetaInputSettings  *input_settings,
 | 
			
		||||
  update_device_natural_scroll (input_settings, device);
 | 
			
		||||
  update_touchpad_tap_enabled (input_settings, device);
 | 
			
		||||
  update_touchpad_send_events (input_settings, device);
 | 
			
		||||
  update_touchpad_scroll_method (input_settings, device);
 | 
			
		||||
  update_touchpad_edge_scroll (input_settings, device);
 | 
			
		||||
  update_touchpad_click_method (input_settings, device);
 | 
			
		||||
 | 
			
		||||
  update_trackball_scroll_button (input_settings, device);
 | 
			
		||||
 
 | 
			
		||||
@@ -414,6 +414,10 @@ gint               meta_monitor_manager_get_monitor_at_point (MetaMonitorManager
 | 
			
		||||
                                                              gfloat              x,
 | 
			
		||||
                                                              gfloat              y);
 | 
			
		||||
 | 
			
		||||
void meta_monitor_manager_clear_output (MetaOutput *output);
 | 
			
		||||
void meta_monitor_manager_clear_mode (MetaMonitorMode *mode);
 | 
			
		||||
void meta_monitor_manager_clear_crtc (MetaCRTC *crtc);
 | 
			
		||||
 | 
			
		||||
/* Returns true if transform causes width and height to be inverted
 | 
			
		||||
   This is true for the odd transforms in the enum */
 | 
			
		||||
static inline gboolean
 | 
			
		||||
 
 | 
			
		||||
@@ -178,7 +178,7 @@ make_logical_config (MetaMonitorManager *manager)
 | 
			
		||||
  unsigned int i, j;
 | 
			
		||||
 | 
			
		||||
  monitor_infos = g_array_sized_new (FALSE, TRUE, sizeof (MetaMonitorInfo),
 | 
			
		||||
                                     manager->n_outputs);
 | 
			
		||||
                                     manager->n_crtcs);
 | 
			
		||||
 | 
			
		||||
  /* Walk the list of MetaCRTCs, and build a MetaMonitorInfo
 | 
			
		||||
     for each of them, unless they reference a rectangle that
 | 
			
		||||
@@ -346,6 +346,23 @@ meta_monitor_manager_constructed (GObject *object)
 | 
			
		||||
  manager->in_init = FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_clear_output (MetaOutput *output)
 | 
			
		||||
{
 | 
			
		||||
  g_free (output->name);
 | 
			
		||||
  g_free (output->vendor);
 | 
			
		||||
  g_free (output->product);
 | 
			
		||||
  g_free (output->serial);
 | 
			
		||||
  g_free (output->modes);
 | 
			
		||||
  g_free (output->possible_crtcs);
 | 
			
		||||
  g_free (output->possible_clones);
 | 
			
		||||
 | 
			
		||||
  if (output->driver_notify)
 | 
			
		||||
    output->driver_notify (output);
 | 
			
		||||
 | 
			
		||||
  memset (output, 0, sizeof (*output));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
 | 
			
		||||
                                        int         n_old_outputs)
 | 
			
		||||
@@ -353,22 +370,22 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_old_outputs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      g_free (old_outputs[i].name);
 | 
			
		||||
      g_free (old_outputs[i].vendor);
 | 
			
		||||
      g_free (old_outputs[i].product);
 | 
			
		||||
      g_free (old_outputs[i].serial);
 | 
			
		||||
      g_free (old_outputs[i].modes);
 | 
			
		||||
      g_free (old_outputs[i].possible_crtcs);
 | 
			
		||||
      g_free (old_outputs[i].possible_clones);
 | 
			
		||||
 | 
			
		||||
      if (old_outputs[i].driver_notify)
 | 
			
		||||
        old_outputs[i].driver_notify (&old_outputs[i]);
 | 
			
		||||
    }
 | 
			
		||||
    meta_monitor_manager_clear_output (&old_outputs[i]);
 | 
			
		||||
 | 
			
		||||
  g_free (old_outputs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_clear_mode (MetaMonitorMode *mode)
 | 
			
		||||
{
 | 
			
		||||
  g_free (mode->name);
 | 
			
		||||
 | 
			
		||||
  if (mode->driver_notify)
 | 
			
		||||
    mode->driver_notify (mode);
 | 
			
		||||
 | 
			
		||||
  memset (mode, 0, sizeof (*mode));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
 | 
			
		||||
                                      int              n_old_modes)
 | 
			
		||||
@@ -376,16 +393,20 @@ meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_old_modes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      g_free (old_modes[i].name);
 | 
			
		||||
 | 
			
		||||
      if (old_modes[i].driver_notify)
 | 
			
		||||
        old_modes[i].driver_notify (&old_modes[i]);
 | 
			
		||||
    }
 | 
			
		||||
    meta_monitor_manager_clear_mode (&old_modes[i]);
 | 
			
		||||
 | 
			
		||||
  g_free (old_modes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_monitor_manager_clear_crtc (MetaCRTC *crtc)
 | 
			
		||||
{
 | 
			
		||||
  if (crtc->driver_notify)
 | 
			
		||||
    crtc->driver_notify (crtc);
 | 
			
		||||
 | 
			
		||||
  memset (crtc, 0, sizeof (*crtc));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_free_crtc_array (MetaCRTC *old_crtcs,
 | 
			
		||||
                                      int       n_old_crtcs)
 | 
			
		||||
@@ -393,10 +414,7 @@ meta_monitor_manager_free_crtc_array (MetaCRTC *old_crtcs,
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_old_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (old_crtcs[i].driver_notify)
 | 
			
		||||
        old_crtcs[i].driver_notify (&old_crtcs[i]);
 | 
			
		||||
    }
 | 
			
		||||
    meta_monitor_manager_clear_crtc (&old_crtcs[i]);
 | 
			
		||||
 | 
			
		||||
  g_free (old_crtcs);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								src/backends/meta-pointer-constraint.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/backends/meta-pointer-constraint.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_constraint_init (MetaPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
 | 
			
		||||
                                   ClutterInputDevice    *device,
 | 
			
		||||
                                   guint32                time,
 | 
			
		||||
                                   float                  prev_x,
 | 
			
		||||
                                   float                  prev_y,
 | 
			
		||||
                                   float                  *x,
 | 
			
		||||
                                   float                  *y)
 | 
			
		||||
{
 | 
			
		||||
  META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint,
 | 
			
		||||
                                                             device,
 | 
			
		||||
                                                             time,
 | 
			
		||||
                                                             prev_x, prev_y,
 | 
			
		||||
                                                             x, y);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								src/backends/meta-pointer-constraint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/backends/meta-pointer-constraint.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_POINTER_CONSTRAINT_H
 | 
			
		||||
#define META_POINTER_CONSTRAINT_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ())
 | 
			
		||||
G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraint, meta_pointer_constraint,
 | 
			
		||||
                          META, POINTER_CONSTRAINT, GObject);
 | 
			
		||||
 | 
			
		||||
struct _MetaPointerConstraintClass
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
 | 
			
		||||
  void (*constrain) (MetaPointerConstraint *constraint,
 | 
			
		||||
                     ClutterInputDevice *device,
 | 
			
		||||
                     guint32 time,
 | 
			
		||||
                     float prev_x,
 | 
			
		||||
                     float prev_y,
 | 
			
		||||
                     float *x,
 | 
			
		||||
                     float *y);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
 | 
			
		||||
                                        ClutterInputDevice    *device,
 | 
			
		||||
                                        guint32                time,
 | 
			
		||||
                                        float                  prev_x,
 | 
			
		||||
                                        float                  prev_y,
 | 
			
		||||
                                        float                 *x,
 | 
			
		||||
                                        float                 *y);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* META_POINTER_CONSTRAINT_H */
 | 
			
		||||
@@ -36,6 +36,10 @@
 | 
			
		||||
#include "meta-monitor-manager-kms.h"
 | 
			
		||||
#include "meta-cursor-renderer-native.h"
 | 
			
		||||
#include "meta-launcher.h"
 | 
			
		||||
#include "backends/meta-cursor-tracker-private.h"
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
struct _MetaBackendNativePrivate
 | 
			
		||||
{
 | 
			
		||||
@@ -137,6 +141,24 @@ constrain_to_barriers (ClutterInputDevice *device,
 | 
			
		||||
                                       new_x, new_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
constrain_to_client_constraint (ClutterInputDevice *device,
 | 
			
		||||
                                guint32             time,
 | 
			
		||||
                                float               prev_x,
 | 
			
		||||
                                float               prev_y,
 | 
			
		||||
                                float              *x,
 | 
			
		||||
                                float              *y)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
  MetaPointerConstraint *constraint = backend->client_pointer_constraint;
 | 
			
		||||
 | 
			
		||||
  if (!constraint)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_pointer_constraint_constrain (constraint, device,
 | 
			
		||||
                                     time, prev_x, prev_y, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
 | 
			
		||||
 * (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
 | 
			
		||||
@@ -191,10 +213,12 @@ constrain_all_screen_monitors (ClutterInputDevice *device,
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_constrain_callback (ClutterInputDevice *device,
 | 
			
		||||
			    guint32             time,
 | 
			
		||||
			    float              *new_x,
 | 
			
		||||
			    float              *new_y,
 | 
			
		||||
			    gpointer            user_data)
 | 
			
		||||
                            guint32             time,
 | 
			
		||||
                            float               prev_x,
 | 
			
		||||
                            float               prev_y,
 | 
			
		||||
                            float              *new_x,
 | 
			
		||||
                            float              *new_y,
 | 
			
		||||
                            gpointer            user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitor_manager;
 | 
			
		||||
  MetaMonitorInfo *monitors;
 | 
			
		||||
@@ -203,6 +227,9 @@ pointer_constrain_callback (ClutterInputDevice *device,
 | 
			
		||||
  /* Constrain to barriers */
 | 
			
		||||
  constrain_to_barriers (device, time, new_x, new_y);
 | 
			
		||||
 | 
			
		||||
  /* Constrain to pointer lock */
 | 
			
		||||
  constrain_to_client_constraint (device, time, prev_x, prev_y, new_x, new_y);
 | 
			
		||||
 | 
			
		||||
  monitor_manager = meta_monitor_manager_get ();
 | 
			
		||||
  monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
 | 
			
		||||
 | 
			
		||||
@@ -253,11 +280,16 @@ meta_backend_native_warp_pointer (MetaBackend *backend,
 | 
			
		||||
{
 | 
			
		||||
  ClutterDeviceManager *manager = clutter_device_manager_get_default ();
 | 
			
		||||
  ClutterInputDevice *device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
 | 
			
		||||
  MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
 | 
			
		||||
 | 
			
		||||
  /* XXX */
 | 
			
		||||
  guint32 time_ = 0;
 | 
			
		||||
 | 
			
		||||
  /* Warp the input device pointer state. */
 | 
			
		||||
  clutter_evdev_warp_pointer (device, time_, x, y);
 | 
			
		||||
 | 
			
		||||
  /* Warp displayed pointer cursor. */
 | 
			
		||||
  meta_cursor_tracker_update_position (tracker, x, y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -304,6 +336,19 @@ meta_backend_native_lock_layout_group (MetaBackend *backend,
 | 
			
		||||
  g_signal_emit_by_name (backend, "keymap-layout-group-changed", idx, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_backend_native_get_relative_motion_deltas (MetaBackend *backend,
 | 
			
		||||
                                                const        ClutterEvent *event,
 | 
			
		||||
                                                double       *dx,
 | 
			
		||||
                                                double       *dy,
 | 
			
		||||
                                                double       *dx_unaccel,
 | 
			
		||||
                                                double       *dy_unaccel)
 | 
			
		||||
{
 | 
			
		||||
  return clutter_evdev_event_get_relative_motion (event,
 | 
			
		||||
                                                  dx, dy,
 | 
			
		||||
                                                  dx_unaccel, dy_unaccel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_native_class_init (MetaBackendNativeClass *klass)
 | 
			
		||||
{
 | 
			
		||||
@@ -321,14 +366,22 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
 | 
			
		||||
  backend_class->set_keymap = meta_backend_native_set_keymap;
 | 
			
		||||
  backend_class->get_keymap = meta_backend_native_get_keymap;
 | 
			
		||||
  backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
 | 
			
		||||
  backend_class->get_relative_motion_deltas = meta_backend_native_get_relative_motion_deltas;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_backend_native_init (MetaBackendNative *native)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  priv->launcher = meta_launcher_new (&error);
 | 
			
		||||
  if (priv->launcher == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Can't initialize KMS backend: %s\n", error->message);
 | 
			
		||||
      exit (1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  priv->launcher = meta_launcher_new ();
 | 
			
		||||
  priv->barrier_manager = meta_barrier_manager_native_new ();
 | 
			
		||||
 | 
			
		||||
  priv->up_client = up_client_new ();
 | 
			
		||||
 
 | 
			
		||||
@@ -93,126 +93,18 @@ next_serial (void)
 | 
			
		||||
  return barrier_serial;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _Vector2
 | 
			
		||||
{
 | 
			
		||||
  float x, y;
 | 
			
		||||
} Vector2;
 | 
			
		||||
 | 
			
		||||
static float
 | 
			
		||||
vector2_cross_product (Vector2 a, Vector2 b)
 | 
			
		||||
{
 | 
			
		||||
  return a.x * b.y - a.y * b.x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Vector2
 | 
			
		||||
vector2_add (Vector2 a, Vector2 b)
 | 
			
		||||
{
 | 
			
		||||
  return (Vector2) {
 | 
			
		||||
    .x = a.x + b.x,
 | 
			
		||||
    .y = a.y + b.y,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Vector2
 | 
			
		||||
vector2_subtract (Vector2 a, Vector2 b)
 | 
			
		||||
{
 | 
			
		||||
  return (Vector2) {
 | 
			
		||||
    .x = a.x - b.x,
 | 
			
		||||
    .y = a.y - b.y,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Vector2
 | 
			
		||||
vector2_multiply_constant (float c, Vector2 a)
 | 
			
		||||
{
 | 
			
		||||
  return (Vector2) {
 | 
			
		||||
    .x = c * a.x,
 | 
			
		||||
    .y = c * a.y,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct _Line2
 | 
			
		||||
{
 | 
			
		||||
  Vector2 a;
 | 
			
		||||
  Vector2 b;
 | 
			
		||||
} Line2;
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
lines_intersect (Line2 *line1, Line2 *line2, Vector2 *intersection)
 | 
			
		||||
{
 | 
			
		||||
  Vector2 p = line1->a;
 | 
			
		||||
  Vector2 r = vector2_subtract (line1->b, line1->a);
 | 
			
		||||
  Vector2 q = line2->a;
 | 
			
		||||
  Vector2 s = vector2_subtract (line2->b, line2->a);
 | 
			
		||||
  float rxs;
 | 
			
		||||
  float sxr;
 | 
			
		||||
  float t;
 | 
			
		||||
  float u;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * The line (p, r) and (q, s) intersects where
 | 
			
		||||
   *
 | 
			
		||||
   *   p + t r = q + u s
 | 
			
		||||
   *
 | 
			
		||||
   * Calculate t:
 | 
			
		||||
   *
 | 
			
		||||
   *   (p + t r) × s = (q + u s) × s
 | 
			
		||||
   *   p × s + t (r × s) = q × s + u (s × s)
 | 
			
		||||
   *   p × s + t (r × s) = q × s
 | 
			
		||||
   *   t (r × s) = q × s - p × s
 | 
			
		||||
   *   t (r × s) = (q - p) × s
 | 
			
		||||
   *   t = ((q - p) × s) / (r × s)
 | 
			
		||||
   *
 | 
			
		||||
   * Using the same method, for u we get:
 | 
			
		||||
   *
 | 
			
		||||
   *   u = ((p - q) × r) / (s × r)
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  rxs = vector2_cross_product (r, s);
 | 
			
		||||
  sxr = vector2_cross_product (s, r);
 | 
			
		||||
 | 
			
		||||
  /* If r × s = 0 then the lines are either parallel or collinear. */
 | 
			
		||||
  if (fabs ( rxs) < DBL_MIN)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  t = vector2_cross_product (vector2_subtract (q, p), s) / rxs;
 | 
			
		||||
  u = vector2_cross_product (vector2_subtract (p, q), r) / sxr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /* The lines only intersect if 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1. */
 | 
			
		||||
  if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  *intersection = vector2_add (p, vector2_multiply_constant (t, r));
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_barrier_horizontal (MetaBarrier *barrier)
 | 
			
		||||
{
 | 
			
		||||
  return barrier->priv->y1 == barrier->priv->y2;
 | 
			
		||||
  return meta_border_is_horizontal (&barrier->priv->border);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_barrier_blocking_directions (MetaBarrier         *barrier,
 | 
			
		||||
                                MetaBarrierDirection directions)
 | 
			
		||||
{
 | 
			
		||||
  /* Barriers doesn't block parallel motions. */
 | 
			
		||||
  if (is_barrier_horizontal (barrier))
 | 
			
		||||
    {
 | 
			
		||||
      if ((directions & (META_BARRIER_DIRECTION_POSITIVE_Y |
 | 
			
		||||
                         META_BARRIER_DIRECTION_NEGATIVE_Y)) == 0)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if ((directions & (META_BARRIER_DIRECTION_POSITIVE_X |
 | 
			
		||||
                         META_BARRIER_DIRECTION_NEGATIVE_X)) == 0)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return (barrier->priv->directions & directions) != directions;
 | 
			
		||||
  return meta_border_is_blocking_directions (&barrier->priv->border,
 | 
			
		||||
                                             directions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -224,31 +116,16 @@ dismiss_pointer (MetaBarrierImplNative *self)
 | 
			
		||||
  priv->state = META_BARRIER_STATE_LEFT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Line2
 | 
			
		||||
barrier_to_line (MetaBarrier *barrier)
 | 
			
		||||
{
 | 
			
		||||
  return (Line2) {
 | 
			
		||||
    .a = (Vector2) {
 | 
			
		||||
      .x = MIN (barrier->priv->x1, barrier->priv->x2),
 | 
			
		||||
      .y = MIN (barrier->priv->y1, barrier->priv->y2),
 | 
			
		||||
    },
 | 
			
		||||
    .b = (Vector2) {
 | 
			
		||||
      .x = MAX (barrier->priv->x1, barrier->priv->x2),
 | 
			
		||||
      .y = MAX (barrier->priv->y1, barrier->priv->y2),
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Calculate the hit box for a held motion. The hit box is a 2 px wide region
 | 
			
		||||
 * in the opposite direction of every direction the barrier blocks. The purpose
 | 
			
		||||
 * of this is to allow small movements without receiving a "left" signal. This
 | 
			
		||||
 * heuristic comes from the X.org pointer barrier implementation.
 | 
			
		||||
 */
 | 
			
		||||
static Line2
 | 
			
		||||
static MetaLine2
 | 
			
		||||
calculate_barrier_hit_box (MetaBarrier *barrier)
 | 
			
		||||
{
 | 
			
		||||
  Line2 hit_box = barrier_to_line (barrier);
 | 
			
		||||
  MetaLine2 hit_box = barrier->priv->border.line;
 | 
			
		||||
 | 
			
		||||
  if (is_barrier_horizontal (barrier))
 | 
			
		||||
    {
 | 
			
		||||
@@ -273,7 +150,8 @@ calculate_barrier_hit_box (MetaBarrier *barrier)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_within_box (Line2 box, Vector2 point)
 | 
			
		||||
is_within_box (MetaLine2   box,
 | 
			
		||||
               MetaVector2 point)
 | 
			
		||||
{
 | 
			
		||||
  return (point.x >= box.a.x && point.x < box.b.x &&
 | 
			
		||||
          point.y >= box.a.y && point.y < box.b.y);
 | 
			
		||||
@@ -288,8 +166,8 @@ maybe_release_barrier (gpointer key,
 | 
			
		||||
  MetaBarrierImplNativePrivate *priv =
 | 
			
		||||
    meta_barrier_impl_native_get_instance_private (self);
 | 
			
		||||
  MetaBarrier *barrier = priv->barrier;
 | 
			
		||||
  Line2 *motion = user_data;
 | 
			
		||||
  Line2 hit_box;
 | 
			
		||||
  MetaLine2 *motion = user_data;
 | 
			
		||||
  MetaLine2 hit_box;
 | 
			
		||||
 | 
			
		||||
  if (priv->state != META_BARRIER_STATE_HELD)
 | 
			
		||||
    return;
 | 
			
		||||
@@ -297,8 +175,10 @@ maybe_release_barrier (gpointer key,
 | 
			
		||||
  /* Release if we end up outside barrier end points. */
 | 
			
		||||
  if (is_barrier_horizontal (barrier))
 | 
			
		||||
    {
 | 
			
		||||
      if (motion->b.x > MAX (barrier->priv->x1, barrier->priv->x2) ||
 | 
			
		||||
          motion->b.x < MIN (barrier->priv->x1, barrier->priv->x2))
 | 
			
		||||
      if (motion->b.x > MAX (barrier->priv->border.line.a.x,
 | 
			
		||||
                             barrier->priv->border.line.b.x) ||
 | 
			
		||||
          motion->b.x < MIN (barrier->priv->border.line.a.x,
 | 
			
		||||
                             barrier->priv->border.line.b.x))
 | 
			
		||||
        {
 | 
			
		||||
          dismiss_pointer (self);
 | 
			
		||||
          return;
 | 
			
		||||
@@ -306,8 +186,10 @@ maybe_release_barrier (gpointer key,
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (motion->b.y > MAX (barrier->priv->y1, barrier->priv->y2) ||
 | 
			
		||||
          motion->b.y < MIN (barrier->priv->y1, barrier->priv->y2))
 | 
			
		||||
      if (motion->b.y > MAX (barrier->priv->border.line.a.y,
 | 
			
		||||
                             barrier->priv->border.line.b.y) ||
 | 
			
		||||
          motion->b.y < MIN (barrier->priv->border.line.a.y,
 | 
			
		||||
                             barrier->priv->border.line.b.y))
 | 
			
		||||
        {
 | 
			
		||||
          dismiss_pointer (self);
 | 
			
		||||
          return;
 | 
			
		||||
@@ -330,7 +212,7 @@ maybe_release_barriers (MetaBarrierManagerNative *manager,
 | 
			
		||||
                        float                     x,
 | 
			
		||||
                        float                     y)
 | 
			
		||||
{
 | 
			
		||||
  Line2 motion = {
 | 
			
		||||
  MetaLine2 motion = {
 | 
			
		||||
    .a = {
 | 
			
		||||
      .x = prev_x,
 | 
			
		||||
      .y = prev_y,
 | 
			
		||||
@@ -350,7 +232,7 @@ typedef struct _MetaClosestBarrierData
 | 
			
		||||
{
 | 
			
		||||
  struct
 | 
			
		||||
  {
 | 
			
		||||
    Line2                       motion;
 | 
			
		||||
    MetaLine2                   motion;
 | 
			
		||||
    MetaBarrierDirection        directions;
 | 
			
		||||
  } in;
 | 
			
		||||
 | 
			
		||||
@@ -371,8 +253,7 @@ update_closest_barrier (gpointer key,
 | 
			
		||||
    meta_barrier_impl_native_get_instance_private (self);
 | 
			
		||||
  MetaBarrier *barrier = priv->barrier;
 | 
			
		||||
  MetaClosestBarrierData *data = user_data;
 | 
			
		||||
  Line2 barrier_line;
 | 
			
		||||
  Vector2 intersection;
 | 
			
		||||
  MetaVector2 intersection;
 | 
			
		||||
  float dx, dy;
 | 
			
		||||
  float distance_2;
 | 
			
		||||
 | 
			
		||||
@@ -391,17 +272,9 @@ update_closest_barrier (gpointer key,
 | 
			
		||||
 | 
			
		||||
  /* Check if the motion intersects with the barrier, and retrieve the
 | 
			
		||||
   * intersection point if any. */
 | 
			
		||||
  barrier_line = (Line2) {
 | 
			
		||||
    .a = {
 | 
			
		||||
      .x = barrier->priv->x1,
 | 
			
		||||
      .y = barrier->priv->y1
 | 
			
		||||
    },
 | 
			
		||||
    .b = {
 | 
			
		||||
      .x = barrier->priv->x2,
 | 
			
		||||
      .y = barrier->priv->y2
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  if (!lines_intersect (&barrier_line, &data->in.motion, &intersection))
 | 
			
		||||
  if (!meta_line2_intersects_with (&barrier->priv->border.line,
 | 
			
		||||
                                   &data->in.motion,
 | 
			
		||||
                                   &intersection))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* Calculate the distance to the barrier and keep track of the closest
 | 
			
		||||
@@ -570,9 +443,9 @@ clamp_to_barrier (MetaBarrierImplNative *self,
 | 
			
		||||
  if (is_barrier_horizontal (barrier))
 | 
			
		||||
    {
 | 
			
		||||
      if (*motion_dir & META_BARRIER_DIRECTION_POSITIVE_Y)
 | 
			
		||||
        *y = barrier->priv->y1;
 | 
			
		||||
        *y = barrier->priv->border.line.a.y;
 | 
			
		||||
      else if (*motion_dir & META_BARRIER_DIRECTION_NEGATIVE_Y)
 | 
			
		||||
        *y = barrier->priv->y1;
 | 
			
		||||
        *y = barrier->priv->border.line.a.y;
 | 
			
		||||
 | 
			
		||||
      priv->blocked_dir = *motion_dir & (META_BARRIER_DIRECTION_POSITIVE_Y |
 | 
			
		||||
                                         META_BARRIER_DIRECTION_NEGATIVE_Y);
 | 
			
		||||
@@ -582,9 +455,9 @@ clamp_to_barrier (MetaBarrierImplNative *self,
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (*motion_dir & META_BARRIER_DIRECTION_POSITIVE_X)
 | 
			
		||||
        *x = barrier->priv->x1;
 | 
			
		||||
        *x = barrier->priv->border.line.a.x;
 | 
			
		||||
      else if (*motion_dir & META_BARRIER_DIRECTION_NEGATIVE_X)
 | 
			
		||||
        *x = barrier->priv->x1;
 | 
			
		||||
        *x = barrier->priv->border.line.a.x;
 | 
			
		||||
 | 
			
		||||
      priv->blocked_dir = *motion_dir & (META_BARRIER_DIRECTION_POSITIVE_X |
 | 
			
		||||
                                         META_BARRIER_DIRECTION_NEGATIVE_X);
 | 
			
		||||
 
 | 
			
		||||
@@ -102,9 +102,6 @@ meta_cursor_renderer_native_finalize (GObject *object)
 | 
			
		||||
  if (priv->animation_timeout_id)
 | 
			
		||||
    g_source_remove (priv->animation_timeout_id);
 | 
			
		||||
 | 
			
		||||
  if (priv->gbm)
 | 
			
		||||
    gbm_device_destroy (priv->gbm);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -258,6 +255,9 @@ has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
 | 
			
		||||
  MetaCursorNativePrivate *cursor_priv =
 | 
			
		||||
    g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
 | 
			
		||||
 | 
			
		||||
  if (!cursor_priv)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  switch (cursor_priv->pending_bo_state)
 | 
			
		||||
    {
 | 
			
		||||
    case META_CURSOR_GBM_BO_STATE_NONE:
 | 
			
		||||
@@ -273,6 +273,32 @@ has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
cursor_over_transformed_crtc (MetaCursorRenderer *renderer,
 | 
			
		||||
                              MetaCursorSprite   *cursor_sprite)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManager *monitors;
 | 
			
		||||
  MetaCRTC *crtcs;
 | 
			
		||||
  unsigned int i, n_crtcs;
 | 
			
		||||
  MetaRectangle rect;
 | 
			
		||||
 | 
			
		||||
  monitors = meta_monitor_manager_get ();
 | 
			
		||||
  meta_monitor_manager_get_resources (monitors, NULL, NULL,
 | 
			
		||||
                                      &crtcs, &n_crtcs, NULL, NULL);
 | 
			
		||||
  rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n_crtcs; i++)
 | 
			
		||||
    {
 | 
			
		||||
      if (!meta_rectangle_overlap (&rect, &crtcs[i].rect))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (crtcs[i].transform != META_MONITOR_TRANSFORM_NORMAL)
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
should_have_hw_cursor (MetaCursorRenderer *renderer,
 | 
			
		||||
                       MetaCursorSprite   *cursor_sprite)
 | 
			
		||||
@@ -282,6 +308,9 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
 | 
			
		||||
  if (!cursor_sprite)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if (cursor_over_transformed_crtc (renderer, cursor_sprite))
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
 | 
			
		||||
  if (!texture)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
@@ -640,7 +669,7 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
 | 
			
		||||
    {
 | 
			
		||||
      CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
 | 
			
		||||
      priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
 | 
			
		||||
      priv->gbm = gbm_create_device (priv->drm_fd);
 | 
			
		||||
      priv->gbm = cogl_kms_renderer_get_gbm (cogl_renderer);
 | 
			
		||||
 | 
			
		||||
      uint64_t width, height;
 | 
			
		||||
      if (drmGetCap (priv->drm_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
 | 
			
		||||
 
 | 
			
		||||
@@ -164,56 +164,36 @@ meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor_native)
 | 
			
		||||
  monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  MetaIdleMonitorNative *monitor_native;
 | 
			
		||||
  GList *fired_watches;
 | 
			
		||||
} CheckNativeClosure;
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
check_native_watch (gpointer key,
 | 
			
		||||
                    gpointer value,
 | 
			
		||||
                    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatchNative *watch_native = value;
 | 
			
		||||
  MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native;
 | 
			
		||||
  CheckNativeClosure *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_native->timeout_source,
 | 
			
		||||
                               closure->monitor_native->last_event_time +
 | 
			
		||||
                               watch->timeout_msec * 1000);
 | 
			
		||||
      steal = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return steal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fire_native_watch (gpointer watch,
 | 
			
		||||
                   gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  _meta_idle_monitor_watch_fire (watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
 | 
			
		||||
  CheckNativeClosure closure;
 | 
			
		||||
  GList *node, *watch_ids;
 | 
			
		||||
 | 
			
		||||
  monitor_native->last_event_time = g_get_monotonic_time ();
 | 
			
		||||
 | 
			
		||||
  closure.monitor_native = monitor_native;
 | 
			
		||||
  closure.fired_watches = NULL;
 | 
			
		||||
  g_hash_table_foreach_steal (monitor->watches, check_native_watch, &closure);
 | 
			
		||||
  watch_ids = g_hash_table_get_keys (monitor->watches);
 | 
			
		||||
 | 
			
		||||
  g_list_foreach (closure.fired_watches, fire_native_watch, NULL);
 | 
			
		||||
  g_list_free (closure.fired_watches);
 | 
			
		||||
  for (node = watch_ids; node != NULL; node = node->next)
 | 
			
		||||
    {
 | 
			
		||||
      guint watch_id = GPOINTER_TO_UINT (node->data);
 | 
			
		||||
      MetaIdleMonitorWatchNative *watch;
 | 
			
		||||
 | 
			
		||||
      watch = g_hash_table_lookup (monitor->watches, GUINT_TO_POINTER (watch_id));
 | 
			
		||||
      if (!watch)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (watch->base.timeout_msec == 0)
 | 
			
		||||
        {
 | 
			
		||||
          _meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          g_source_set_ready_time (watch->timeout_source,
 | 
			
		||||
                                   monitor_native->last_event_time +
 | 
			
		||||
                                   watch->base.timeout_msec * 1000);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free (watch_ids);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -154,30 +154,30 @@ device_set_click_method (struct libinput_device            *libinput_device,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_input_settings_native_set_scroll_method (MetaInputSettings            *settings,
 | 
			
		||||
                                              ClutterInputDevice           *device,
 | 
			
		||||
                                              GDesktopTouchpadScrollMethod  mode)
 | 
			
		||||
meta_input_settings_native_set_edge_scroll (MetaInputSettings            *settings,
 | 
			
		||||
                                            ClutterInputDevice           *device,
 | 
			
		||||
                                            gboolean                      edge_scrolling_enabled)
 | 
			
		||||
{
 | 
			
		||||
  enum libinput_config_scroll_method scroll_method = 0;
 | 
			
		||||
  struct libinput_device *libinput_device;
 | 
			
		||||
  enum libinput_config_scroll_method supported;
 | 
			
		||||
 | 
			
		||||
  libinput_device = clutter_evdev_input_device_get_libinput_device (device);
 | 
			
		||||
  supported = libinput_device_config_scroll_get_methods (libinput_device);
 | 
			
		||||
 | 
			
		||||
  switch (mode)
 | 
			
		||||
  if (supported & LIBINPUT_CONFIG_SCROLL_2FG)
 | 
			
		||||
    {
 | 
			
		||||
    case G_DESKTOP_TOUCHPAD_SCROLL_METHOD_DISABLED:
 | 
			
		||||
      scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
 | 
			
		||||
      break;
 | 
			
		||||
    case G_DESKTOP_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING:
 | 
			
		||||
      scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
 | 
			
		||||
      break;
 | 
			
		||||
    case G_DESKTOP_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING:
 | 
			
		||||
      scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      g_assert_not_reached ();
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
    }
 | 
			
		||||
  else if (supported & LIBINPUT_CONFIG_SCROLL_EDGE &&
 | 
			
		||||
           edge_scrolling_enabled)
 | 
			
		||||
    {
 | 
			
		||||
      scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  device_set_scroll_method (libinput_device, scroll_method);
 | 
			
		||||
}
 | 
			
		||||
@@ -252,7 +252,7 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
 | 
			
		||||
  input_settings_class->set_left_handed = meta_input_settings_native_set_left_handed;
 | 
			
		||||
  input_settings_class->set_tap_enabled = meta_input_settings_native_set_tap_enabled;
 | 
			
		||||
  input_settings_class->set_invert_scroll = meta_input_settings_native_set_invert_scroll;
 | 
			
		||||
  input_settings_class->set_scroll_method = meta_input_settings_native_set_scroll_method;
 | 
			
		||||
  input_settings_class->set_edge_scroll = meta_input_settings_native_set_edge_scroll;
 | 
			
		||||
  input_settings_class->set_scroll_button = meta_input_settings_native_set_scroll_button;
 | 
			
		||||
  input_settings_class->set_click_method = meta_input_settings_native_set_click_method;
 | 
			
		||||
  input_settings_class->set_keyboard_repeat = meta_input_settings_native_set_keyboard_repeat;
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,12 @@
 | 
			
		||||
#include "meta-cursor-renderer-native.h"
 | 
			
		||||
#include "meta-idle-monitor-native.h"
 | 
			
		||||
 | 
			
		||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevDevice, g_object_unref)
 | 
			
		||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevClient, g_object_unref)
 | 
			
		||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUdevEnumerator, g_object_unref)
 | 
			
		||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Login1Session, g_object_unref)
 | 
			
		||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(Login1Seat, g_object_unref)
 | 
			
		||||
 | 
			
		||||
struct _MetaLauncher
 | 
			
		||||
{
 | 
			
		||||
  Login1Session *session_proxy;
 | 
			
		||||
@@ -54,30 +60,22 @@ struct _MetaLauncher
 | 
			
		||||
  gboolean session_active;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
report_error_and_die (const char *prefix,
 | 
			
		||||
                      GError *error)
 | 
			
		||||
{
 | 
			
		||||
  /* if a function returns due to g_return_val_if_fail,
 | 
			
		||||
   * then the error may not be set */
 | 
			
		||||
  if (error)
 | 
			
		||||
    g_error ("%s: %s", prefix, error->message);
 | 
			
		||||
  else
 | 
			
		||||
    g_error ("%s", prefix);
 | 
			
		||||
 | 
			
		||||
  /* the error is not freed, but it is ok as g_error aborts the process */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Login1Session *
 | 
			
		||||
get_session_proxy (GCancellable *cancellable)
 | 
			
		||||
get_session_proxy (GCancellable *cancellable,
 | 
			
		||||
                   GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  char *proxy_path;
 | 
			
		||||
  char *session_id;
 | 
			
		||||
  g_autofree char *proxy_path = NULL;
 | 
			
		||||
  g_autofree char *session_id = NULL;
 | 
			
		||||
  Login1Session *session_proxy;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  if (sd_pid_get_session (getpid (), &session_id) < 0)
 | 
			
		||||
    return NULL;
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "Could not get session ID: %m");
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
 | 
			
		||||
 | 
			
		||||
@@ -85,26 +83,24 @@ get_session_proxy (GCancellable *cancellable)
 | 
			
		||||
                                                         G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 | 
			
		||||
                                                         "org.freedesktop.login1",
 | 
			
		||||
                                                         proxy_path,
 | 
			
		||||
                                                         cancellable, &error);
 | 
			
		||||
                                                         cancellable, error);
 | 
			
		||||
  if (!session_proxy)
 | 
			
		||||
    report_error_and_die ("Failed getting session proxy", error);
 | 
			
		||||
 | 
			
		||||
  free (proxy_path);
 | 
			
		||||
    g_prefix_error(error, "Could not get session proxy: ");
 | 
			
		||||
 | 
			
		||||
  return session_proxy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Login1Seat *
 | 
			
		||||
get_seat_proxy (GCancellable *cancellable)
 | 
			
		||||
get_seat_proxy (GCancellable *cancellable,
 | 
			
		||||
                GError      **error)
 | 
			
		||||
{
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  Login1Seat *seat = login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 | 
			
		||||
                                                         G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 | 
			
		||||
                                                         "org.freedesktop.login1",
 | 
			
		||||
                                                         "/org/freedesktop/login1/seat/self",
 | 
			
		||||
                                                         cancellable, &error);
 | 
			
		||||
                                                         cancellable, error);
 | 
			
		||||
  if (!seat)
 | 
			
		||||
    report_error_and_die ("Could not get seat proxy", error);
 | 
			
		||||
    g_prefix_error(error, "Could not get seat proxy: ");
 | 
			
		||||
 | 
			
		||||
  return seat;
 | 
			
		||||
}
 | 
			
		||||
@@ -293,8 +289,8 @@ get_primary_gpu_path (const gchar *seat_name)
 | 
			
		||||
  gchar *path = NULL;
 | 
			
		||||
  GList *devices, *tmp;
 | 
			
		||||
 | 
			
		||||
  GUdevClient *gudev_client = g_udev_client_new (subsystems);
 | 
			
		||||
  GUdevEnumerator *enumerator = g_udev_enumerator_new (gudev_client);
 | 
			
		||||
  g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
 | 
			
		||||
  g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
 | 
			
		||||
 | 
			
		||||
  g_udev_enumerator_add_match_name (enumerator, "card*");
 | 
			
		||||
  g_udev_enumerator_add_match_tag (enumerator, "seat");
 | 
			
		||||
@@ -305,7 +301,8 @@ get_primary_gpu_path (const gchar *seat_name)
 | 
			
		||||
 | 
			
		||||
  for (tmp = devices; tmp != NULL; tmp = tmp->next)
 | 
			
		||||
    {
 | 
			
		||||
      GUdevDevice *pci_device;
 | 
			
		||||
      g_autoptr (GUdevDevice) platform_device = NULL;
 | 
			
		||||
      g_autoptr (GUdevDevice) pci_device = NULL;
 | 
			
		||||
      GUdevDevice *dev = tmp->data;
 | 
			
		||||
      gint boot_vga;
 | 
			
		||||
      const gchar *device_seat;
 | 
			
		||||
@@ -332,94 +329,138 @@ get_primary_gpu_path (const gchar *seat_name)
 | 
			
		||||
      if (g_strcmp0 (seat_name, device_seat))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
 | 
			
		||||
      if (!pci_device)
 | 
			
		||||
          continue;
 | 
			
		||||
 | 
			
		||||
      /* get value of boot_vga attribute or 0 if the device has no boot_vga */
 | 
			
		||||
      boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga");
 | 
			
		||||
      g_object_unref (pci_device);
 | 
			
		||||
 | 
			
		||||
      if (boot_vga == 1)
 | 
			
		||||
      platform_device = g_udev_device_get_parent_with_subsystem (dev, "platform", NULL);
 | 
			
		||||
      if (platform_device != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          /* found the boot_vga device */
 | 
			
		||||
          path = g_strdup (g_udev_device_get_device_file (dev));
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
 | 
			
		||||
      if (pci_device != NULL)
 | 
			
		||||
        {
 | 
			
		||||
          /* get value of boot_vga attribute or 0 if the device has no boot_vga */
 | 
			
		||||
          boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga");
 | 
			
		||||
          if (boot_vga == 1)
 | 
			
		||||
            {
 | 
			
		||||
              /* found the boot_vga device */
 | 
			
		||||
              path = g_strdup (g_udev_device_get_device_file (dev));
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (devices, g_object_unref);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
  g_object_unref (enumerator);
 | 
			
		||||
  g_object_unref (gudev_client);
 | 
			
		||||
 | 
			
		||||
  return path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static gboolean
 | 
			
		||||
get_kms_fd (Login1Session *session_proxy,
 | 
			
		||||
            const gchar *seat_id,
 | 
			
		||||
            int *fd_out)
 | 
			
		||||
            const gchar   *seat_id,
 | 
			
		||||
            int           *fd_out,
 | 
			
		||||
            GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  int major, minor;
 | 
			
		||||
  int fd;
 | 
			
		||||
  gchar *path;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  path = get_primary_gpu_path (seat_id);
 | 
			
		||||
  g_autofree gchar *path = get_primary_gpu_path (seat_id);
 | 
			
		||||
  if (!path)
 | 
			
		||||
    g_error ("could not find drm kms device");
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "could not find drm kms device");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!get_device_info_from_path (path, &major, &minor))
 | 
			
		||||
    g_error ("Could not stat %s: %m", path);
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "Could not get device info for path %s: %m", path);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (path);
 | 
			
		||||
 | 
			
		||||
  if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
 | 
			
		||||
    report_error_and_die ("Could not open DRM device", error);
 | 
			
		||||
  if (!take_device (session_proxy, major, minor, &fd, NULL, error))
 | 
			
		||||
    {
 | 
			
		||||
      g_prefix_error (error, "Could not open DRM device: ");
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  *fd_out = fd;
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gchar *
 | 
			
		||||
get_seat_id (void)
 | 
			
		||||
get_seat_id (GError **error)
 | 
			
		||||
{
 | 
			
		||||
  char *session_id, *seat_id = NULL;
 | 
			
		||||
  g_autofree char *session_id = NULL;
 | 
			
		||||
  char *seat_id = NULL;
 | 
			
		||||
  int r;
 | 
			
		||||
 | 
			
		||||
  if (sd_pid_get_session (0, &session_id) < 0)
 | 
			
		||||
    return NULL;
 | 
			
		||||
  r = sd_pid_get_session (0, &session_id);
 | 
			
		||||
  if (r < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "Could not get session for PID: %s", g_strerror (-r));
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* on error the seat_id will remain NULL */
 | 
			
		||||
  sd_session_get_seat (session_id, &seat_id);
 | 
			
		||||
  free (session_id);
 | 
			
		||||
  r = sd_session_get_seat (session_id, &seat_id);
 | 
			
		||||
  if (r < 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                   "Could not get seat for session: %s", g_strerror (-r));
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return seat_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaLauncher *
 | 
			
		||||
meta_launcher_new (void)
 | 
			
		||||
meta_launcher_new (GError **error)
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *self = NULL;
 | 
			
		||||
  Login1Session *session_proxy;
 | 
			
		||||
  char *seat_id;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  g_autoptr (Login1Session) session_proxy = NULL;
 | 
			
		||||
  g_autoptr (Login1Seat) seat_proxy = NULL;
 | 
			
		||||
  g_autofree char *seat_id = NULL;
 | 
			
		||||
  gboolean have_control = FALSE;
 | 
			
		||||
  int kms_fd;
 | 
			
		||||
 | 
			
		||||
  session_proxy = get_session_proxy (NULL);
 | 
			
		||||
  if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
 | 
			
		||||
    report_error_and_die ("Could not take control", error);
 | 
			
		||||
  session_proxy = get_session_proxy (NULL, error);
 | 
			
		||||
  if (!session_proxy)
 | 
			
		||||
    goto fail;
 | 
			
		||||
 | 
			
		||||
  seat_id = get_seat_id ();
 | 
			
		||||
  if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, error))
 | 
			
		||||
    {
 | 
			
		||||
      g_prefix_error (error, "Could not take control: ");
 | 
			
		||||
      goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  have_control = TRUE;
 | 
			
		||||
 | 
			
		||||
  seat_id = get_seat_id (error);
 | 
			
		||||
  if (!seat_id)
 | 
			
		||||
    g_error ("Failed getting seat id");
 | 
			
		||||
    goto fail;
 | 
			
		||||
 | 
			
		||||
  get_kms_fd (session_proxy, seat_id, &kms_fd);
 | 
			
		||||
  free (seat_id);
 | 
			
		||||
  seat_proxy = get_seat_proxy (NULL, error);
 | 
			
		||||
  if (!seat_proxy)
 | 
			
		||||
    goto fail;
 | 
			
		||||
 | 
			
		||||
  if (!get_kms_fd (session_proxy, seat_id, &kms_fd, error))
 | 
			
		||||
    goto fail;
 | 
			
		||||
 | 
			
		||||
  self = g_slice_new0 (MetaLauncher);
 | 
			
		||||
  self->session_proxy = session_proxy;
 | 
			
		||||
  self->seat_proxy = get_seat_proxy (NULL);
 | 
			
		||||
  self->session_proxy = g_object_ref (session_proxy);
 | 
			
		||||
  self->seat_proxy = g_object_ref (seat_proxy);
 | 
			
		||||
 | 
			
		||||
  self->session_active = TRUE;
 | 
			
		||||
 | 
			
		||||
@@ -429,8 +470,12 @@ meta_launcher_new (void)
 | 
			
		||||
                                      self);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
 | 
			
		||||
 | 
			
		||||
  return self;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
  if (have_control)
 | 
			
		||||
    login1_session_call_release_control_sync (session_proxy, NULL, NULL);
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaLauncher MetaLauncher;
 | 
			
		||||
 | 
			
		||||
MetaLauncher     *meta_launcher_new                     (void);
 | 
			
		||||
MetaLauncher     *meta_launcher_new                     (GError       **error);
 | 
			
		||||
void              meta_launcher_free                    (MetaLauncher  *self);
 | 
			
		||||
 | 
			
		||||
gboolean          meta_launcher_activate_session        (MetaLauncher  *self,
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,8 @@
 | 
			
		||||
 | 
			
		||||
#include <gudev/gudev.h>
 | 
			
		||||
 | 
			
		||||
#define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  drmModeConnector *connector;
 | 
			
		||||
 | 
			
		||||
@@ -66,6 +68,9 @@ typedef struct {
 | 
			
		||||
  uint32_t underscan_prop_id;
 | 
			
		||||
  uint32_t underscan_hborder_prop_id;
 | 
			
		||||
  uint32_t underscan_vborder_prop_id;
 | 
			
		||||
  uint32_t primary_plane_id;
 | 
			
		||||
  uint32_t rotation_prop_id;
 | 
			
		||||
  uint32_t rotation_map[ALL_TRANSFORMS];
 | 
			
		||||
} MetaCRTCKms;
 | 
			
		||||
 | 
			
		||||
struct _MetaMonitorManagerKms
 | 
			
		||||
@@ -429,6 +434,137 @@ get_output_scale (MetaMonitorManager *manager,
 | 
			
		||||
    return compute_scale (output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
find_property_index (MetaMonitorManager         *manager,
 | 
			
		||||
                     drmModeObjectPropertiesPtr  props,
 | 
			
		||||
                     const gchar                *prop_name,
 | 
			
		||||
                     drmModePropertyPtr         *found)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < props->count_props; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModePropertyPtr prop;
 | 
			
		||||
 | 
			
		||||
      prop = drmModeGetProperty (manager_kms->fd, props->props[i]);
 | 
			
		||||
      if (!prop)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (strcmp (prop->name, prop_name) == 0)
 | 
			
		||||
        {
 | 
			
		||||
          *found = prop;
 | 
			
		||||
          return i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      drmModeFreeProperty (prop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_transforms (MetaMonitorManager *manager,
 | 
			
		||||
                  drmModePropertyPtr  prop,
 | 
			
		||||
                  MetaCRTC           *crtc)
 | 
			
		||||
{
 | 
			
		||||
  MetaCRTCKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < prop->count_enums; i++)
 | 
			
		||||
    {
 | 
			
		||||
      int cur = -1;
 | 
			
		||||
 | 
			
		||||
      if (strcmp (prop->enums[i].name, "rotate-0") == 0)
 | 
			
		||||
        cur = META_MONITOR_TRANSFORM_NORMAL;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
 | 
			
		||||
        cur = META_MONITOR_TRANSFORM_90;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
 | 
			
		||||
        cur = META_MONITOR_TRANSFORM_180;
 | 
			
		||||
      else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
 | 
			
		||||
        cur = META_MONITOR_TRANSFORM_270;
 | 
			
		||||
 | 
			
		||||
      if (cur != -1)
 | 
			
		||||
        {
 | 
			
		||||
          crtc->all_transforms |= 1 << cur;
 | 
			
		||||
          crtc_kms->rotation_map[cur] = 1 << prop->enums[i].value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_primary_plane (MetaMonitorManager         *manager,
 | 
			
		||||
                  drmModeObjectPropertiesPtr  props)
 | 
			
		||||
{
 | 
			
		||||
  drmModePropertyPtr prop;
 | 
			
		||||
  int idx;
 | 
			
		||||
 | 
			
		||||
  idx = find_property_index (manager, props, "type", &prop);
 | 
			
		||||
  if (idx < 0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  drmModeFreeProperty (prop);
 | 
			
		||||
  return props->prop_values[idx] == DRM_PLANE_TYPE_PRIMARY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_crtc_rotations (MetaMonitorManager *manager,
 | 
			
		||||
                     MetaCRTC           *crtc,
 | 
			
		||||
                     unsigned int        idx)
 | 
			
		||||
{
 | 
			
		||||
  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
 | 
			
		||||
  drmModeObjectPropertiesPtr props;
 | 
			
		||||
  drmModePlaneRes *planes;
 | 
			
		||||
  drmModePlane *drm_plane;
 | 
			
		||||
  MetaCRTCKms *crtc_kms;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  crtc_kms = crtc->driver_private;
 | 
			
		||||
 | 
			
		||||
  planes = drmModeGetPlaneResources(manager_kms->fd);
 | 
			
		||||
  if (planes == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < planes->count_planes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      drmModePropertyPtr prop;
 | 
			
		||||
 | 
			
		||||
      drm_plane = drmModeGetPlane (manager_kms->fd, planes->planes[i]);
 | 
			
		||||
 | 
			
		||||
      if (!drm_plane)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if ((drm_plane->possible_crtcs & (1 << idx)))
 | 
			
		||||
        {
 | 
			
		||||
          props = drmModeObjectGetProperties (manager_kms->fd,
 | 
			
		||||
                                              drm_plane->plane_id,
 | 
			
		||||
                                              DRM_MODE_OBJECT_PLANE);
 | 
			
		||||
 | 
			
		||||
          if (props && is_primary_plane (manager, props))
 | 
			
		||||
            {
 | 
			
		||||
              int rotation_idx;
 | 
			
		||||
 | 
			
		||||
              crtc_kms->primary_plane_id = drm_plane->plane_id;
 | 
			
		||||
              rotation_idx = find_property_index (manager, props, "rotation", &prop);
 | 
			
		||||
 | 
			
		||||
              if (rotation_idx >= 0)
 | 
			
		||||
                {
 | 
			
		||||
                  crtc_kms->rotation_prop_id = props->props[rotation_idx];
 | 
			
		||||
                  parse_transforms (manager, prop, crtc);
 | 
			
		||||
                  drmModeFreeProperty (prop);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          if (props)
 | 
			
		||||
            drmModeFreeObjectProperties (props);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      drmModeFreePlane (drm_plane);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  drmModeFreePlaneResources (planes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
 | 
			
		||||
{
 | 
			
		||||
@@ -496,8 +632,18 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
 | 
			
		||||
      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));
 | 
			
		||||
 | 
			
		||||
      /* Calculate refresh rate in milliHz first for extra precision. */
 | 
			
		||||
      meta_mode->refresh_rate = (mode->clock * 1000000LL) / mode->htotal;
 | 
			
		||||
      meta_mode->refresh_rate += (mode->vtotal / 2);
 | 
			
		||||
      meta_mode->refresh_rate /= mode->vtotal;
 | 
			
		||||
      if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 | 
			
		||||
	meta_mode->refresh_rate *= 2;
 | 
			
		||||
      if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 | 
			
		||||
        meta_mode->refresh_rate /= 2;
 | 
			
		||||
      if (mode->vscan > 1)
 | 
			
		||||
        meta_mode->refresh_rate /= mode->vscan;
 | 
			
		||||
      meta_mode->refresh_rate /= 1000.0;
 | 
			
		||||
 | 
			
		||||
      meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
 | 
			
		||||
      meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
 | 
			
		||||
@@ -546,6 +692,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
 | 
			
		||||
      meta_crtc->driver_private = g_new0 (MetaCRTCKms, 1);
 | 
			
		||||
      meta_crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
 | 
			
		||||
      find_crtc_properties (manager_kms, meta_crtc);
 | 
			
		||||
      init_crtc_rotations (manager, meta_crtc, i);
 | 
			
		||||
 | 
			
		||||
      drmModeFreeCrtc (crtc);
 | 
			
		||||
    }
 | 
			
		||||
@@ -928,6 +1075,7 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
    {
 | 
			
		||||
      MetaCRTCInfo *crtc_info = crtcs[i];
 | 
			
		||||
      MetaCRTC *crtc = crtc_info->crtc;
 | 
			
		||||
      MetaCRTCKms *crtc_kms = crtc->driver_private;
 | 
			
		||||
      CoglKmsCrtc *cogl_crtc;
 | 
			
		||||
 | 
			
		||||
      crtc->is_dirty = TRUE;
 | 
			
		||||
@@ -1000,6 +1148,13 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
 | 
			
		||||
          crtc->current_mode = mode;
 | 
			
		||||
          crtc->transform = crtc_info->transform;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (crtc->all_transforms & (1 << crtc->transform))
 | 
			
		||||
        drmModeObjectSetProperty (manager_kms->fd,
 | 
			
		||||
                                  crtc_kms->primary_plane_id,
 | 
			
		||||
                                  DRM_MODE_OBJECT_PLANE,
 | 
			
		||||
                                  crtc_kms->rotation_prop_id,
 | 
			
		||||
                                  crtc_kms->rotation_map[crtc->transform]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
 | 
			
		||||
@@ -1152,6 +1307,8 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
 | 
			
		||||
 | 
			
		||||
  manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
 | 
			
		||||
 | 
			
		||||
  drmSetClientCap (manager_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
 | 
			
		||||
 | 
			
		||||
  const char *subsystems[2] = { "drm", NULL };
 | 
			
		||||
  manager_kms->udev = g_udev_client_new (subsystems);
 | 
			
		||||
  g_signal_connect (manager_kms->udev, "uevent",
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,7 @@ struct _MetaBackendX11Private
 | 
			
		||||
  gchar *keymap_layouts;
 | 
			
		||||
  gchar *keymap_variants;
 | 
			
		||||
  gchar *keymap_options;
 | 
			
		||||
  int locked_group;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _MetaBackendX11Private MetaBackendX11Private;
 | 
			
		||||
 | 
			
		||||
@@ -297,15 +298,23 @@ handle_host_xevent (MetaBackend *backend,
 | 
			
		||||
 | 
			
		||||
  if (event->type == priv->xkb_event_base)
 | 
			
		||||
    {
 | 
			
		||||
      XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
 | 
			
		||||
      XkbEvent *xkb_ev = (XkbEvent *) event;
 | 
			
		||||
 | 
			
		||||
      if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID)
 | 
			
		||||
      if (xkb_ev->any.device == META_VIRTUAL_CORE_KEYBOARD_ID)
 | 
			
		||||
        {
 | 
			
		||||
          switch (xkb_ev->xkb_type)
 | 
			
		||||
          switch (xkb_ev->any.xkb_type)
 | 
			
		||||
            {
 | 
			
		||||
            case XkbNewKeyboardNotify:
 | 
			
		||||
            case XkbMapNotify:
 | 
			
		||||
              keymap_changed (backend);
 | 
			
		||||
              break;
 | 
			
		||||
            case XkbStateNotify:
 | 
			
		||||
              if (xkb_ev->state.changed & XkbGroupLockMask)
 | 
			
		||||
                {
 | 
			
		||||
                  if (priv->locked_group != xkb_ev->state.locked_group)
 | 
			
		||||
                    XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, priv->locked_group);
 | 
			
		||||
                }
 | 
			
		||||
              break;
 | 
			
		||||
            default:
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
@@ -776,6 +785,7 @@ meta_backend_x11_lock_layout_group (MetaBackend *backend,
 | 
			
		||||
  MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
 | 
			
		||||
  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
 | 
			
		||||
 | 
			
		||||
  priv->locked_group = idx;
 | 
			
		||||
  XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -107,6 +107,7 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
 | 
			
		||||
  MetaDisplay *display = barrier->priv->display;
 | 
			
		||||
  Display *dpy;
 | 
			
		||||
  Window root;
 | 
			
		||||
  unsigned int allowed_motion_dirs;
 | 
			
		||||
 | 
			
		||||
  if (display == NULL)
 | 
			
		||||
    {
 | 
			
		||||
@@ -121,12 +122,14 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
 | 
			
		||||
  dpy = display->xdisplay;
 | 
			
		||||
  root = DefaultRootWindow (dpy);
 | 
			
		||||
 | 
			
		||||
  allowed_motion_dirs =
 | 
			
		||||
    meta_border_get_allows_directions (&barrier->priv->border);
 | 
			
		||||
  priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
 | 
			
		||||
                                               barrier->priv->x1,
 | 
			
		||||
                                               barrier->priv->y1,
 | 
			
		||||
                                               barrier->priv->x2,
 | 
			
		||||
                                               barrier->priv->y2,
 | 
			
		||||
                                               barrier->priv->directions,
 | 
			
		||||
                                               barrier->priv->border.line.a.x,
 | 
			
		||||
                                               barrier->priv->border.line.a.y,
 | 
			
		||||
                                               barrier->priv->border.line.b.x,
 | 
			
		||||
                                               barrier->priv->border.line.b.y,
 | 
			
		||||
                                               allowed_motion_dirs,
 | 
			
		||||
                                               0, NULL);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_insert (display->xids, &priv->xbarrier, barrier);
 | 
			
		||||
 
 | 
			
		||||
@@ -107,20 +107,6 @@ set_alarm_enabled (Display    *dpy,
 | 
			
		||||
  XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
check_x11_watch (gpointer data,
 | 
			
		||||
                 gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorWatchXSync *watch_xsync = data;
 | 
			
		||||
  MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync;
 | 
			
		||||
  XSyncAlarm alarm = (XSyncAlarm) user_data;
 | 
			
		||||
 | 
			
		||||
  if (watch_xsync->xalarm != alarm)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  _meta_idle_monitor_watch_fire (watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
counter_name_for_device (int device_id)
 | 
			
		||||
{
 | 
			
		||||
@@ -327,13 +313,38 @@ meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor_xsync)
 | 
			
		||||
  monitor_xsync->alarms = g_hash_table_new (NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
check_x11_watches (MetaIdleMonitor *monitor,
 | 
			
		||||
                   XSyncAlarm       alarm)
 | 
			
		||||
{
 | 
			
		||||
  GList *node, *watch_ids;
 | 
			
		||||
 | 
			
		||||
  /* we get the keys and do explicit look ups in case
 | 
			
		||||
   * an early iteration of the loop ends up leading
 | 
			
		||||
   * to watches from later iterations getting invalidated
 | 
			
		||||
   */
 | 
			
		||||
  watch_ids = g_hash_table_get_keys (monitor->watches);
 | 
			
		||||
 | 
			
		||||
  for (node = watch_ids; node != NULL; node = node->next)
 | 
			
		||||
    {
 | 
			
		||||
      guint watch_id = GPOINTER_TO_UINT (node->data);
 | 
			
		||||
      MetaIdleMonitorWatchXSync *watch;
 | 
			
		||||
 | 
			
		||||
      watch = g_hash_table_lookup (monitor->watches, GUINT_TO_POINTER (watch_id));
 | 
			
		||||
 | 
			
		||||
      if (watch && watch->xalarm == alarm)
 | 
			
		||||
        _meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_list_free (watch_ids);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor       *monitor,
 | 
			
		||||
                                       XSyncAlarmNotifyEvent *alarm_event)
 | 
			
		||||
{
 | 
			
		||||
  MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
 | 
			
		||||
  XSyncAlarm alarm;
 | 
			
		||||
  GList *watches;
 | 
			
		||||
  gboolean has_alarm;
 | 
			
		||||
 | 
			
		||||
  if (alarm_event->state != XSyncAlarmActive)
 | 
			
		||||
@@ -358,10 +369,5 @@ meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor       *monitor,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (has_alarm)
 | 
			
		||||
    {
 | 
			
		||||
      watches = g_hash_table_get_values (monitor->watches);
 | 
			
		||||
 | 
			
		||||
      g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
 | 
			
		||||
      g_list_free (watches);
 | 
			
		||||
    }
 | 
			
		||||
    check_x11_watches (monitor, alarm);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -199,9 +199,9 @@ meta_input_settings_x11_set_invert_scroll (MetaInputSettings  *settings,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_input_settings_x11_set_scroll_method (MetaInputSettings            *settings,
 | 
			
		||||
                                           ClutterInputDevice           *device,
 | 
			
		||||
                                           GDesktopTouchpadScrollMethod  mode)
 | 
			
		||||
meta_input_settings_x11_set_edge_scroll (MetaInputSettings            *settings,
 | 
			
		||||
                                         ClutterInputDevice           *device,
 | 
			
		||||
                                         gboolean                      edge_scroll_enabled)
 | 
			
		||||
{
 | 
			
		||||
  guchar values[3] = { 0 }; /* 2fg, edge, button. The last value is unused */
 | 
			
		||||
  guchar *available;
 | 
			
		||||
@@ -211,26 +211,21 @@ meta_input_settings_x11_set_scroll_method (MetaInputSettings            *setting
 | 
			
		||||
  if (!available)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  switch (mode)
 | 
			
		||||
  if (available[0])
 | 
			
		||||
    {
 | 
			
		||||
    case G_DESKTOP_TOUCHPAD_SCROLL_METHOD_DISABLED:
 | 
			
		||||
      break;
 | 
			
		||||
    case G_DESKTOP_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING:
 | 
			
		||||
      values[1] = 1;
 | 
			
		||||
      break;
 | 
			
		||||
    case G_DESKTOP_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING:
 | 
			
		||||
      values[0] = 1;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      g_assert_not_reached ();
 | 
			
		||||
    }
 | 
			
		||||
  else if (available[1] && edge_scroll_enabled)
 | 
			
		||||
    {
 | 
			
		||||
      values[1] = 1;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Disabled */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if ((values[0] && !available[0]) || (values[1] && !available[1]))
 | 
			
		||||
    g_warning ("Device '%s' does not support scroll mode %d\n",
 | 
			
		||||
               clutter_input_device_get_device_name (device), mode);
 | 
			
		||||
  else
 | 
			
		||||
    change_property (device, "libinput Scroll Method Enabled",
 | 
			
		||||
                     XA_INTEGER, 8, &values, 3);
 | 
			
		||||
  change_property (device, "libinput Scroll Method Enabled",
 | 
			
		||||
                   XA_INTEGER, 8, &values, 3);
 | 
			
		||||
 | 
			
		||||
  meta_XFree (available);
 | 
			
		||||
}
 | 
			
		||||
@@ -321,7 +316,7 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
 | 
			
		||||
  input_settings_class->set_left_handed = meta_input_settings_x11_set_left_handed;
 | 
			
		||||
  input_settings_class->set_tap_enabled = meta_input_settings_x11_set_tap_enabled;
 | 
			
		||||
  input_settings_class->set_invert_scroll = meta_input_settings_x11_set_invert_scroll;
 | 
			
		||||
  input_settings_class->set_scroll_method = meta_input_settings_x11_set_scroll_method;
 | 
			
		||||
  input_settings_class->set_edge_scroll = meta_input_settings_x11_set_edge_scroll;
 | 
			
		||||
  input_settings_class->set_scroll_button = meta_input_settings_x11_set_scroll_button;
 | 
			
		||||
  input_settings_class->set_click_method = meta_input_settings_x11_set_click_method;
 | 
			
		||||
  input_settings_class->set_keyboard_repeat = meta_input_settings_x11_set_keyboard_repeat;
 | 
			
		||||
 
 | 
			
		||||
@@ -419,12 +419,6 @@ read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
      result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!result)
 | 
			
		||||
    {
 | 
			
		||||
      edid_atom = XInternAtom (manager_xrandr->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE);
 | 
			
		||||
      result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (result)
 | 
			
		||||
    {
 | 
			
		||||
      if (len > 0 && len % 128 == 0)
 | 
			
		||||
@@ -637,6 +631,70 @@ output_get_connector_type (MetaMonitorManagerXrandr *manager_xrandr,
 | 
			
		||||
  return META_CONNECTOR_TYPE_Unknown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_get_modes (MetaMonitorManager *manager,
 | 
			
		||||
                  MetaOutput         *meta_output,
 | 
			
		||||
                  XRROutputInfo      *output)
 | 
			
		||||
{
 | 
			
		||||
  guint j, k;
 | 
			
		||||
  guint n_actual_modes;
 | 
			
		||||
 | 
			
		||||
  meta_output->modes = g_new0 (MetaMonitorMode *, output->nmode);
 | 
			
		||||
 | 
			
		||||
  n_actual_modes = 0;
 | 
			
		||||
  for (j = 0; j < (guint)output->nmode; j++)
 | 
			
		||||
    {
 | 
			
		||||
      for (k = 0; k < manager->n_modes; k++)
 | 
			
		||||
        {
 | 
			
		||||
          if (output->modes[j] == (XID)manager->modes[k].mode_id)
 | 
			
		||||
            {
 | 
			
		||||
              meta_output->modes[n_actual_modes] = &manager->modes[k];
 | 
			
		||||
              n_actual_modes += 1;
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  meta_output->n_modes = n_actual_modes;
 | 
			
		||||
  if (n_actual_modes > 0)
 | 
			
		||||
    meta_output->preferred_mode = meta_output->modes[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_get_crtcs (MetaMonitorManager *manager,
 | 
			
		||||
                  MetaOutput         *meta_output,
 | 
			
		||||
                  XRROutputInfo      *output)
 | 
			
		||||
{
 | 
			
		||||
  guint j, k;
 | 
			
		||||
  guint n_actual_crtcs;
 | 
			
		||||
 | 
			
		||||
  meta_output->possible_crtcs = g_new0 (MetaCRTC *, output->ncrtc);
 | 
			
		||||
 | 
			
		||||
  n_actual_crtcs = 0;
 | 
			
		||||
  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[n_actual_crtcs] = &manager->crtcs[k];
 | 
			
		||||
              n_actual_crtcs += 1;
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  meta_output->n_possible_crtcs = n_actual_crtcs;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
get_xmode_name (XRRModeInfo *xmode)
 | 
			
		||||
{
 | 
			
		||||
@@ -773,6 +831,8 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
 | 
			
		||||
      MetaOutput *meta_output;
 | 
			
		||||
 | 
			
		||||
      output = XRRGetOutputInfo (manager_xrandr->xdisplay, resources, resources->outputs[i]);
 | 
			
		||||
      if (!output)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      meta_output = &manager->outputs[n_actual_outputs];
 | 
			
		||||
 | 
			
		||||
@@ -796,44 +856,8 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
 | 
			
		||||
          meta_output->connector_type = output_get_connector_type (manager_xrandr, meta_output);
 | 
			
		||||
 | 
			
		||||
	  output_get_tile_info (manager_xrandr, meta_output);
 | 
			
		||||
	  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;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	  output_get_modes (manager, meta_output, output);
 | 
			
		||||
          output_get_crtcs (manager, meta_output, output);
 | 
			
		||||
 | 
			
		||||
	  meta_output->n_possible_clones = output->nclone;
 | 
			
		||||
	  meta_output->possible_clones = g_new0 (MetaOutput *, meta_output->n_possible_clones);
 | 
			
		||||
@@ -857,7 +881,10 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
 | 
			
		||||
	  else
 | 
			
		||||
	    meta_output->backlight = -1;
 | 
			
		||||
 | 
			
		||||
	  n_actual_outputs++;
 | 
			
		||||
          if (meta_output->n_modes == 0 || meta_output->n_possible_crtcs == 0)
 | 
			
		||||
            meta_monitor_manager_clear_output (meta_output);
 | 
			
		||||
          else
 | 
			
		||||
            n_actual_outputs++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      XRRFreeOutputInfo (output);
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,14 @@
 | 
			
		||||
 | 
			
		||||
#include "compositor/region-utils.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PAINTING,
 | 
			
		||||
 | 
			
		||||
  LAST_SIGNAL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint signals[LAST_SIGNAL];
 | 
			
		||||
 | 
			
		||||
struct _MetaSurfaceActorWaylandPrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
@@ -347,12 +355,13 @@ meta_surface_actor_wayland_paint (ClutterActor *actor)
 | 
			
		||||
  if (priv->surface)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandCompositor *compositor = priv->surface->compositor;
 | 
			
		||||
      meta_wayland_surface_update_outputs (priv->surface);
 | 
			
		||||
 | 
			
		||||
      wl_list_insert_list (&compositor->frame_callbacks, &priv->frame_callback_list);
 | 
			
		||||
      wl_list_init (&priv->frame_callback_list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (actor, signals[PAINTING], 0);
 | 
			
		||||
 | 
			
		||||
  CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -388,6 +397,13 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
 | 
			
		||||
  surface_actor_class->get_window = meta_surface_actor_wayland_get_window;
 | 
			
		||||
 | 
			
		||||
  object_class->dispose = meta_surface_actor_wayland_dispose;
 | 
			
		||||
 | 
			
		||||
  signals[PAINTING] = g_signal_new ("painting",
 | 
			
		||||
                                    G_TYPE_FROM_CLASS (object_class),
 | 
			
		||||
                                    G_SIGNAL_RUN_LAST,
 | 
			
		||||
                                    0,
 | 
			
		||||
                                    NULL, NULL, NULL,
 | 
			
		||||
                                    G_TYPE_NONE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -255,6 +255,31 @@ get_actor_private (MetaWindowActor *actor)
 | 
			
		||||
  return priv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ClutterTimeline *
 | 
			
		||||
actor_animate (ClutterActor         *actor,
 | 
			
		||||
               ClutterAnimationMode  mode,
 | 
			
		||||
               guint                 duration,
 | 
			
		||||
               const gchar          *first_property,
 | 
			
		||||
               ...)
 | 
			
		||||
{
 | 
			
		||||
  va_list args;
 | 
			
		||||
  ClutterTransition *transition;
 | 
			
		||||
 | 
			
		||||
  clutter_actor_save_easing_state (actor);
 | 
			
		||||
  clutter_actor_set_easing_mode (actor, mode);
 | 
			
		||||
  clutter_actor_set_easing_duration (actor, duration);
 | 
			
		||||
 | 
			
		||||
  va_start (args, first_property);
 | 
			
		||||
  g_object_set_valist (G_OBJECT (actor), first_property, args);
 | 
			
		||||
  va_end (args);
 | 
			
		||||
 | 
			
		||||
  transition = clutter_actor_get_transition (actor, first_property);
 | 
			
		||||
 | 
			
		||||
  clutter_actor_restore_easing_state (actor);
 | 
			
		||||
 | 
			
		||||
  return CLUTTER_TIMELINE (transition);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
 | 
			
		||||
{
 | 
			
		||||
@@ -271,7 +296,10 @@ on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data)
 | 
			
		||||
 | 
			
		||||
      if (apriv->orig_parent)
 | 
			
		||||
        {
 | 
			
		||||
          clutter_actor_reparent (a, apriv->orig_parent);
 | 
			
		||||
          g_object_ref (a);
 | 
			
		||||
          clutter_actor_remove_child (clutter_actor_get_parent (a), a);
 | 
			
		||||
          clutter_actor_add_child (apriv->orig_parent, a);
 | 
			
		||||
          g_object_unref (a);
 | 
			
		||||
          apriv->orig_parent = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -360,11 +388,10 @@ switch_workspace (MetaPlugin *plugin,
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
  MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv;
 | 
			
		||||
  GList        *l;
 | 
			
		||||
  ClutterActor *workspace0  = clutter_group_new ();
 | 
			
		||||
  ClutterActor *workspace1  = clutter_group_new ();
 | 
			
		||||
  ClutterActor *workspace0  = clutter_actor_new ();
 | 
			
		||||
  ClutterActor *workspace1  = clutter_actor_new ();
 | 
			
		||||
  ClutterActor *stage;
 | 
			
		||||
  int           screen_width, screen_height;
 | 
			
		||||
  ClutterAnimation *animation;
 | 
			
		||||
 | 
			
		||||
  screen = meta_plugin_get_screen (plugin);
 | 
			
		||||
  stage = meta_get_stage_for_screen (screen);
 | 
			
		||||
@@ -373,17 +400,15 @@ switch_workspace (MetaPlugin *plugin,
 | 
			
		||||
                        &screen_width,
 | 
			
		||||
                        &screen_height);
 | 
			
		||||
 | 
			
		||||
  clutter_actor_set_anchor_point (workspace1,
 | 
			
		||||
                                  screen_width,
 | 
			
		||||
                                  screen_height);
 | 
			
		||||
  clutter_actor_set_pivot_point (workspace1, 1.0, 1.0);
 | 
			
		||||
  clutter_actor_set_position (workspace1,
 | 
			
		||||
                              screen_width,
 | 
			
		||||
                              screen_height);
 | 
			
		||||
 | 
			
		||||
  clutter_actor_set_scale (workspace1, 0.0, 0.0);
 | 
			
		||||
 | 
			
		||||
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace1);
 | 
			
		||||
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace0);
 | 
			
		||||
  clutter_actor_add_child (stage, workspace1);
 | 
			
		||||
  clutter_actor_add_child (stage, workspace0);
 | 
			
		||||
 | 
			
		||||
  if (from == to)
 | 
			
		||||
    {
 | 
			
		||||
@@ -406,12 +431,15 @@ switch_workspace (MetaPlugin *plugin,
 | 
			
		||||
 | 
			
		||||
      if (win_workspace == to || win_workspace == from)
 | 
			
		||||
        {
 | 
			
		||||
          ClutterActor *parent = win_workspace == to ? workspace1 : workspace0;
 | 
			
		||||
          apriv->orig_parent = clutter_actor_get_parent (actor);
 | 
			
		||||
 | 
			
		||||
          clutter_actor_reparent (actor,
 | 
			
		||||
				  win_workspace == to ? workspace1 : workspace0);
 | 
			
		||||
          clutter_actor_show_all (actor);
 | 
			
		||||
          clutter_actor_raise_top (actor);
 | 
			
		||||
          g_object_ref (actor);
 | 
			
		||||
          clutter_actor_remove_child (clutter_actor_get_parent (actor), actor);
 | 
			
		||||
          clutter_actor_add_child (parent, actor);
 | 
			
		||||
          clutter_actor_show (actor);
 | 
			
		||||
          clutter_actor_set_child_below_sibling (parent, actor, NULL);
 | 
			
		||||
          g_object_unref (actor);
 | 
			
		||||
        }
 | 
			
		||||
      else if (win_workspace < 0)
 | 
			
		||||
        {
 | 
			
		||||
@@ -431,23 +459,21 @@ switch_workspace (MetaPlugin *plugin,
 | 
			
		||||
  priv->desktop1 = workspace0;
 | 
			
		||||
  priv->desktop2 = workspace1;
 | 
			
		||||
 | 
			
		||||
  animation = clutter_actor_animate (workspace0, CLUTTER_EASE_IN_SINE,
 | 
			
		||||
                                     SWITCH_TIMEOUT,
 | 
			
		||||
                                     "scale-x", 1.0,
 | 
			
		||||
                                     "scale-y", 1.0,
 | 
			
		||||
                                     NULL);
 | 
			
		||||
  priv->tml_switch_workspace1 = clutter_animation_get_timeline (animation);
 | 
			
		||||
  priv->tml_switch_workspace1 = actor_animate (workspace0, CLUTTER_EASE_IN_SINE,
 | 
			
		||||
                                               SWITCH_TIMEOUT,
 | 
			
		||||
                                               "scale-x", 1.0,
 | 
			
		||||
                                               "scale-y", 1.0,
 | 
			
		||||
                                               NULL);
 | 
			
		||||
  g_signal_connect (priv->tml_switch_workspace1,
 | 
			
		||||
                    "completed",
 | 
			
		||||
                    G_CALLBACK (on_switch_workspace_effect_complete),
 | 
			
		||||
                    plugin);
 | 
			
		||||
 | 
			
		||||
  animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE,
 | 
			
		||||
                                     SWITCH_TIMEOUT,
 | 
			
		||||
                                     "scale-x", 0.0,
 | 
			
		||||
                                     "scale-y", 0.0,
 | 
			
		||||
                                     NULL);
 | 
			
		||||
  priv->tml_switch_workspace2 = clutter_animation_get_timeline (animation);
 | 
			
		||||
  priv->tml_switch_workspace2 = actor_animate (workspace1, CLUTTER_EASE_IN_SINE,
 | 
			
		||||
                                               SWITCH_TIMEOUT,
 | 
			
		||||
                                               "scale-x", 0.0,
 | 
			
		||||
                                               "scale-y", 0.0,
 | 
			
		||||
                                               NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -504,19 +530,17 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
 | 
			
		||||
 | 
			
		||||
  if (type == META_WINDOW_NORMAL)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterAnimation *animation;
 | 
			
		||||
      EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
 | 
			
		||||
      ActorPrivate *apriv = get_actor_private (window_actor);
 | 
			
		||||
 | 
			
		||||
      animation = clutter_actor_animate (actor,
 | 
			
		||||
                                         CLUTTER_EASE_IN_SINE,
 | 
			
		||||
                                         MINIMIZE_TIMEOUT,
 | 
			
		||||
                                         "scale-x", 0.0,
 | 
			
		||||
                                         "scale-y", 0.0,
 | 
			
		||||
                                         "x", (double)icon_geometry.x,
 | 
			
		||||
                                         "y", (double)icon_geometry.y,
 | 
			
		||||
                                         NULL);
 | 
			
		||||
      apriv->tml_minimize = clutter_animation_get_timeline (animation);
 | 
			
		||||
      apriv->tml_minimize = actor_animate (actor,
 | 
			
		||||
                                           CLUTTER_EASE_IN_SINE,
 | 
			
		||||
                                           MINIMIZE_TIMEOUT,
 | 
			
		||||
                                           "scale-x", 0.0,
 | 
			
		||||
                                           "scale-y", 0.0,
 | 
			
		||||
                                           "x", (double)icon_geometry.x,
 | 
			
		||||
                                           "y", (double)icon_geometry.y,
 | 
			
		||||
                                           NULL);
 | 
			
		||||
      data->plugin = plugin;
 | 
			
		||||
      data->actor = actor;
 | 
			
		||||
      g_signal_connect (apriv->tml_minimize, "completed",
 | 
			
		||||
@@ -561,7 +585,6 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
 | 
			
		||||
 | 
			
		||||
  if (type == META_WINDOW_NORMAL)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterAnimation *animation;
 | 
			
		||||
      EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
 | 
			
		||||
      ActorPrivate *apriv = get_actor_private (window_actor);
 | 
			
		||||
 | 
			
		||||
@@ -570,14 +593,13 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
 | 
			
		||||
      clutter_actor_set_scale (actor, 0.5, 0.5);
 | 
			
		||||
      clutter_actor_show (actor);
 | 
			
		||||
 | 
			
		||||
      animation = clutter_actor_animate (actor,
 | 
			
		||||
                                         CLUTTER_EASE_OUT_QUAD,
 | 
			
		||||
                                         MAP_TIMEOUT,
 | 
			
		||||
                                         "opacity", 255,
 | 
			
		||||
                                         "scale-x", 1.0,
 | 
			
		||||
                                         "scale-y", 1.0,
 | 
			
		||||
                                         NULL);
 | 
			
		||||
      apriv->tml_map = clutter_animation_get_timeline (animation);
 | 
			
		||||
      apriv->tml_map = actor_animate (actor,
 | 
			
		||||
                                      CLUTTER_EASE_OUT_QUAD,
 | 
			
		||||
                                      MAP_TIMEOUT,
 | 
			
		||||
                                      "opacity", 255,
 | 
			
		||||
                                      "scale-x", 1.0,
 | 
			
		||||
                                      "scale-y", 1.0,
 | 
			
		||||
                                      NULL);
 | 
			
		||||
      data->actor = actor;
 | 
			
		||||
      data->plugin = plugin;
 | 
			
		||||
      g_signal_connect (apriv->tml_map, "completed",
 | 
			
		||||
@@ -618,18 +640,16 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
 | 
			
		||||
 | 
			
		||||
  if (type == META_WINDOW_NORMAL)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterAnimation *animation;
 | 
			
		||||
      EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
 | 
			
		||||
      ActorPrivate *apriv = get_actor_private (window_actor);
 | 
			
		||||
 | 
			
		||||
      animation = clutter_actor_animate (actor,
 | 
			
		||||
                                         CLUTTER_EASE_OUT_QUAD,
 | 
			
		||||
                                         DESTROY_TIMEOUT,
 | 
			
		||||
                                         "opacity", 0,
 | 
			
		||||
                                         "scale-x", 0.8,
 | 
			
		||||
                                         "scale-y", 0.8,
 | 
			
		||||
                                         NULL);
 | 
			
		||||
      apriv->tml_destroy = clutter_animation_get_timeline (animation);
 | 
			
		||||
      apriv->tml_destroy = actor_animate (actor,
 | 
			
		||||
                                          CLUTTER_EASE_OUT_QUAD,
 | 
			
		||||
                                          DESTROY_TIMEOUT,
 | 
			
		||||
                                          "opacity", 0,
 | 
			
		||||
                                          "scale-x", 0.8,
 | 
			
		||||
                                          "scale-y", 0.8,
 | 
			
		||||
                                          NULL);
 | 
			
		||||
      data->plugin = plugin;
 | 
			
		||||
      data->actor = actor;
 | 
			
		||||
      g_signal_connect (apriv->tml_destroy, "completed",
 | 
			
		||||
@@ -702,7 +722,9 @@ show_tile_preview (MetaPlugin    *plugin,
 | 
			
		||||
  clutter_actor_show (preview->actor);
 | 
			
		||||
 | 
			
		||||
  window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
 | 
			
		||||
  clutter_actor_lower (preview->actor, window_actor);
 | 
			
		||||
  clutter_actor_set_child_below_sibling (clutter_actor_get_parent (preview->actor),
 | 
			
		||||
                                         preview->actor,
 | 
			
		||||
                                         window_actor);
 | 
			
		||||
 | 
			
		||||
  preview->tile_rect = *tile_rect;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@
 | 
			
		||||
#include <meta/boxes.h>
 | 
			
		||||
#include <meta/display.h>
 | 
			
		||||
#include "keybindings-private.h"
 | 
			
		||||
#include "startup-notification-private.h"
 | 
			
		||||
#include "meta-gesture-tracker-private.h"
 | 
			
		||||
#include <meta/prefs.h>
 | 
			
		||||
#include <meta/barrier.h>
 | 
			
		||||
@@ -276,9 +277,8 @@ struct _MetaDisplay
 | 
			
		||||
  int xinput_event_base;
 | 
			
		||||
  int xinput_opcode;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  SnDisplay *sn_display;
 | 
			
		||||
#endif
 | 
			
		||||
  MetaStartupNotification *startup_notification;
 | 
			
		||||
 | 
			
		||||
  int xsync_event_base;
 | 
			
		||||
  int xsync_error_base;
 | 
			
		||||
  int shape_event_base;
 | 
			
		||||
 
 | 
			
		||||
@@ -400,28 +400,6 @@ meta_display_remove_pending_pings_for_window (MetaDisplay *display,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
static void
 | 
			
		||||
sn_error_trap_push (SnDisplay *sn_display,
 | 
			
		||||
                    Display   *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  display = meta_display_for_x_display (xdisplay);
 | 
			
		||||
  if (display != NULL)
 | 
			
		||||
    meta_error_trap_push (display);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sn_error_trap_pop (SnDisplay *sn_display,
 | 
			
		||||
                   Display   *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  display = meta_display_for_x_display (xdisplay);
 | 
			
		||||
  if (display != NULL)
 | 
			
		||||
    meta_error_trap_pop (display);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
enable_compositor (MetaDisplay *display)
 | 
			
		||||
{
 | 
			
		||||
@@ -527,6 +505,20 @@ gesture_tracker_state_changed (MetaGestureTracker   *tracker,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_startup_notification_changed (MetaStartupNotification *sn,
 | 
			
		||||
                                 gpointer                 sequence,
 | 
			
		||||
                                 MetaDisplay             *display)
 | 
			
		||||
{
 | 
			
		||||
  if (!display->screen)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_slist_free (display->screen->startup_sequences);
 | 
			
		||||
  display->screen->startup_sequences =
 | 
			
		||||
    meta_startup_notification_get_sequences (display->startup_notification);
 | 
			
		||||
  g_signal_emit_by_name (display->screen, "startup-sequence-changed", sequence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_display_open:
 | 
			
		||||
 *
 | 
			
		||||
@@ -630,12 +622,6 @@ meta_display_open (void)
 | 
			
		||||
 | 
			
		||||
  display->screen = NULL;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  display->sn_display = sn_display_new (display->xdisplay,
 | 
			
		||||
                                        sn_error_trap_push,
 | 
			
		||||
                                        sn_error_trap_pop);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Get events */
 | 
			
		||||
  meta_display_init_events (display);
 | 
			
		||||
  meta_display_init_events_x11 (display);
 | 
			
		||||
@@ -916,6 +902,10 @@ meta_display_open (void)
 | 
			
		||||
 | 
			
		||||
  display->screen = screen;
 | 
			
		||||
 | 
			
		||||
  display->startup_notification = meta_startup_notification_get (display);
 | 
			
		||||
  g_signal_connect (display->startup_notification, "changed",
 | 
			
		||||
                    G_CALLBACK (on_startup_notification_changed), display);
 | 
			
		||||
 | 
			
		||||
  meta_screen_init_workspaces (screen);
 | 
			
		||||
 | 
			
		||||
  enable_compositor (display);
 | 
			
		||||
@@ -1100,6 +1090,7 @@ meta_display_close (MetaDisplay *display,
 | 
			
		||||
 | 
			
		||||
  meta_display_remove_autoraise_callback (display);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&display->startup_notification);
 | 
			
		||||
  g_clear_object (&display->gesture_tracker);
 | 
			
		||||
 | 
			
		||||
  if (display->focus_timeout_id)
 | 
			
		||||
@@ -1112,14 +1103,6 @@ meta_display_close (MetaDisplay *display,
 | 
			
		||||
 | 
			
		||||
  meta_screen_free (display->screen, timestamp);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  if (display->sn_display)
 | 
			
		||||
    {
 | 
			
		||||
      sn_display_unref (display->sn_display);
 | 
			
		||||
      display->sn_display = NULL;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Must be after all calls to meta_window_unmanage() since they
 | 
			
		||||
   * unregister windows
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -182,10 +182,25 @@ meta_display_handle_event (MetaDisplay        *display,
 | 
			
		||||
  sequence = clutter_event_get_event_sequence (event);
 | 
			
		||||
 | 
			
		||||
  /* Set the pointer emulating sequence on touch begin, if eligible */
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_BEGIN &&
 | 
			
		||||
      !display->pointer_emulating_sequence &&
 | 
			
		||||
      sequence_is_pointer_emulated (display, event))
 | 
			
		||||
    display->pointer_emulating_sequence = sequence;
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_BEGIN)
 | 
			
		||||
    {
 | 
			
		||||
      if (sequence_is_pointer_emulated (display, event))
 | 
			
		||||
        {
 | 
			
		||||
          /* This is the new pointer emulating sequence */
 | 
			
		||||
          display->pointer_emulating_sequence = sequence;
 | 
			
		||||
        }
 | 
			
		||||
      else if (display->pointer_emulating_sequence == sequence)
 | 
			
		||||
        {
 | 
			
		||||
          /* This sequence was "pointer emulating" in a prior incarnation,
 | 
			
		||||
           * but now it isn't. We unset the pointer emulating sequence at
 | 
			
		||||
           * this point so the current sequence is not mistaken as pointer
 | 
			
		||||
           * emulating, while we've ensured that it's been deemed
 | 
			
		||||
           * "pointer emulating" throughout all of the event processing
 | 
			
		||||
           * of the previous incarnation.
 | 
			
		||||
           */
 | 
			
		||||
          display->pointer_emulating_sequence = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  MetaWaylandCompositor *compositor = NULL;
 | 
			
		||||
@@ -335,11 +350,6 @@ meta_display_handle_event (MetaDisplay        *display,
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Unset the pointer emulating sequence after its end event is processed */
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_END &&
 | 
			
		||||
      display->pointer_emulating_sequence == sequence)
 | 
			
		||||
    display->pointer_emulating_sequence = NULL;
 | 
			
		||||
 | 
			
		||||
  display->current_time = CurrentTime;
 | 
			
		||||
  return bypass_clutter;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								src/core/main.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/core/main.c
									
									
									
									
									
								
							@@ -80,6 +80,10 @@
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "wayland/meta-wayland.h"
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_NATIVE_BACKEND) && defined(HAVE_WAYLAND)
 | 
			
		||||
#include <systemd/sd-login.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -291,6 +295,95 @@ on_sigterm (gpointer user_data)
 | 
			
		||||
  return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_WAYLAND) && defined(HAVE_NATIVE_BACKEND)
 | 
			
		||||
static char *
 | 
			
		||||
find_logind_session_type (void)
 | 
			
		||||
{
 | 
			
		||||
  char **sessions;
 | 
			
		||||
  char *session_id;
 | 
			
		||||
  char *session_type;
 | 
			
		||||
  int ret, i;
 | 
			
		||||
 | 
			
		||||
  ret = sd_pid_get_session (0, &session_id);
 | 
			
		||||
 | 
			
		||||
  if (ret == 0 && session_id != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      ret = sd_session_get_type (session_id, &session_type);
 | 
			
		||||
      free (session_id);
 | 
			
		||||
 | 
			
		||||
      if (ret < 0)
 | 
			
		||||
        session_type = NULL;
 | 
			
		||||
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
  session_type = NULL;
 | 
			
		||||
 | 
			
		||||
  ret = sd_uid_get_sessions (getuid (), TRUE, &sessions);
 | 
			
		||||
 | 
			
		||||
  if (ret < 0 || sessions == NULL)
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; sessions[i] != NULL; i++)
 | 
			
		||||
    {
 | 
			
		||||
      ret = sd_session_get_type (sessions[i], &session_type);
 | 
			
		||||
 | 
			
		||||
      if (ret < 0)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (g_strcmp0 (session_type, "x11") == 0||
 | 
			
		||||
          g_strcmp0 (session_type, "wayland") == 0)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      g_clear_pointer (&session_type, (GDestroyNotify) free);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  for (i = 0; sessions[i] != NULL; i++)
 | 
			
		||||
    free (sessions[i]);
 | 
			
		||||
  free (sessions);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
  return session_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
check_for_wayland_session_type (void)
 | 
			
		||||
{
 | 
			
		||||
  char *session_type = NULL;
 | 
			
		||||
  gboolean is_wayland = FALSE;
 | 
			
		||||
 | 
			
		||||
  session_type = find_logind_session_type ();
 | 
			
		||||
 | 
			
		||||
  if (session_type != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      is_wayland = g_strcmp0 (session_type, "wayland") == 0;
 | 
			
		||||
      free (session_type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return is_wayland;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_backend (void)
 | 
			
		||||
{
 | 
			
		||||
  gboolean session_type_is_wayland = FALSE;
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_WAYLAND) && defined(HAVE_NATIVE_BACKEND)
 | 
			
		||||
  session_type_is_wayland = check_for_wayland_session_type ();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(CLUTTER_WINDOWING_EGL) && defined(HAVE_NATIVE_BACKEND)
 | 
			
		||||
  if (opt_display_server || session_type_is_wayland)
 | 
			
		||||
    clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
 | 
			
		||||
  else
 | 
			
		||||
#endif
 | 
			
		||||
    clutter_set_windowing_backend (CLUTTER_WINDOWING_X11);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  meta_set_is_wayland_compositor (opt_wayland || session_type_is_wayland);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_init: (skip)
 | 
			
		||||
 *
 | 
			
		||||
@@ -323,16 +416,7 @@ meta_init (void)
 | 
			
		||||
  if (g_getenv ("MUTTER_DEBUG"))
 | 
			
		||||
    meta_set_debugging (TRUE);
 | 
			
		||||
 | 
			
		||||
#if defined(CLUTTER_WINDOWING_EGL) && defined(HAVE_NATIVE_BACKEND)
 | 
			
		||||
  if (opt_display_server)
 | 
			
		||||
    clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
 | 
			
		||||
  else
 | 
			
		||||
#endif
 | 
			
		||||
    clutter_set_windowing_backend (CLUTTER_WINDOWING_X11);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  meta_set_is_wayland_compositor (opt_wayland);
 | 
			
		||||
#endif
 | 
			
		||||
  init_backend ();
 | 
			
		||||
 | 
			
		||||
  if (g_get_home_dir ())
 | 
			
		||||
    if (chdir (g_get_home_dir ()) < 0)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										154
									
								
								src/core/meta-border.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/core/meta-border.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "core/meta-border.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
static inline float
 | 
			
		||||
meta_vector2_cross_product (const MetaVector2 a,
 | 
			
		||||
                            const MetaVector2 b)
 | 
			
		||||
{
 | 
			
		||||
  return a.x * b.y - a.y * b.x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline MetaVector2
 | 
			
		||||
meta_vector2_add (const MetaVector2 a,
 | 
			
		||||
                  const MetaVector2 b)
 | 
			
		||||
{
 | 
			
		||||
  return (MetaVector2) {
 | 
			
		||||
    .x = a.x + b.x,
 | 
			
		||||
    .y = a.y + b.y,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline MetaVector2
 | 
			
		||||
meta_vector2_multiply_constant (const float       c,
 | 
			
		||||
                                const MetaVector2 a)
 | 
			
		||||
{
 | 
			
		||||
  return (MetaVector2) {
 | 
			
		||||
    .x = c * a.x,
 | 
			
		||||
    .y = c * a.y,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_line2_intersects_with (const MetaLine2 *line1,
 | 
			
		||||
                            const MetaLine2 *line2,
 | 
			
		||||
                            MetaVector2     *intersection)
 | 
			
		||||
{
 | 
			
		||||
  MetaVector2 p = line1->a;
 | 
			
		||||
  MetaVector2 r = meta_vector2_subtract (line1->b, line1->a);
 | 
			
		||||
  MetaVector2 q = line2->a;
 | 
			
		||||
  MetaVector2 s = meta_vector2_subtract (line2->b, line2->a);
 | 
			
		||||
  float rxs;
 | 
			
		||||
  float sxr;
 | 
			
		||||
  float t;
 | 
			
		||||
  float u;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * The line (p, r) and (q, s) intersects where
 | 
			
		||||
   *
 | 
			
		||||
   *   p + t r = q + u s
 | 
			
		||||
   *
 | 
			
		||||
   * Calculate t:
 | 
			
		||||
   *
 | 
			
		||||
   *   (p + t r) × s = (q + u s) × s
 | 
			
		||||
   *   p × s + t (r × s) = q × s + u (s × s)
 | 
			
		||||
   *   p × s + t (r × s) = q × s
 | 
			
		||||
   *   t (r × s) = q × s - p × s
 | 
			
		||||
   *   t (r × s) = (q - p) × s
 | 
			
		||||
   *   t = ((q - p) × s) / (r × s)
 | 
			
		||||
   *
 | 
			
		||||
   * Using the same method, for u we get:
 | 
			
		||||
   *
 | 
			
		||||
   *   u = ((p - q) × r) / (s × r)
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  rxs = meta_vector2_cross_product (r, s);
 | 
			
		||||
  sxr = meta_vector2_cross_product (s, r);
 | 
			
		||||
 | 
			
		||||
  /* If r × s = 0 then the lines are either parallel or collinear. */
 | 
			
		||||
  if (fabsf (rxs) < FLT_MIN)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  t = meta_vector2_cross_product (meta_vector2_subtract (q, p), s) / rxs;
 | 
			
		||||
  u = meta_vector2_cross_product (meta_vector2_subtract (p, q), r) / sxr;
 | 
			
		||||
 | 
			
		||||
  /* The lines only intersect if 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1. */
 | 
			
		||||
  if (t < 0.0 || t > 1.0 || u < 0.0 || u > 1.0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  *intersection = meta_vector2_add (p, meta_vector2_multiply_constant (t, r));
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_border_is_horizontal (MetaBorder *border)
 | 
			
		||||
{
 | 
			
		||||
  return border->line.a.y == border->line.b.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_border_is_blocking_directions (MetaBorder               *border,
 | 
			
		||||
                                    MetaBorderMotionDirection directions)
 | 
			
		||||
{
 | 
			
		||||
  if (meta_border_is_horizontal (border))
 | 
			
		||||
    {
 | 
			
		||||
      if ((directions & (META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
 | 
			
		||||
                         META_BORDER_MOTION_DIRECTION_NEGATIVE_Y)) == 0)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if ((directions & (META_BORDER_MOTION_DIRECTION_POSITIVE_X |
 | 
			
		||||
                         META_BORDER_MOTION_DIRECTION_NEGATIVE_X)) == 0)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return (~border->blocking_directions & directions) != directions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int
 | 
			
		||||
meta_border_get_allows_directions (MetaBorder *border)
 | 
			
		||||
{
 | 
			
		||||
  return ~border->blocking_directions &
 | 
			
		||||
    (META_BORDER_MOTION_DIRECTION_POSITIVE_X |
 | 
			
		||||
     META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
 | 
			
		||||
     META_BORDER_MOTION_DIRECTION_NEGATIVE_X |
 | 
			
		||||
     META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_border_set_allows_directions (MetaBorder *border, unsigned int directions)
 | 
			
		||||
{
 | 
			
		||||
  border->blocking_directions =
 | 
			
		||||
    ~directions & (META_BORDER_MOTION_DIRECTION_POSITIVE_X |
 | 
			
		||||
                   META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
 | 
			
		||||
                   META_BORDER_MOTION_DIRECTION_NEGATIVE_X |
 | 
			
		||||
                   META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								src/core/meta-border.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/core/meta-border.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_BORDER_H
 | 
			
		||||
#define META_BORDER_H
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_BORDER_MOTION_DIRECTION_POSITIVE_X = 1 << 0,
 | 
			
		||||
  META_BORDER_MOTION_DIRECTION_POSITIVE_Y = 1 << 1,
 | 
			
		||||
  META_BORDER_MOTION_DIRECTION_NEGATIVE_X = 1 << 2,
 | 
			
		||||
  META_BORDER_MOTION_DIRECTION_NEGATIVE_Y = 1 << 3,
 | 
			
		||||
} MetaBorderMotionDirection;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaVector2
 | 
			
		||||
{
 | 
			
		||||
  float x;
 | 
			
		||||
  float y;
 | 
			
		||||
} MetaVector2;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaLine2
 | 
			
		||||
{
 | 
			
		||||
  MetaVector2 a;
 | 
			
		||||
  MetaVector2 b;
 | 
			
		||||
} MetaLine2;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaBorder
 | 
			
		||||
{
 | 
			
		||||
  MetaLine2 line;
 | 
			
		||||
  MetaBorderMotionDirection blocking_directions;
 | 
			
		||||
} MetaBorder;
 | 
			
		||||
 | 
			
		||||
static inline MetaVector2
 | 
			
		||||
meta_vector2_subtract (const MetaVector2 a,
 | 
			
		||||
                       const MetaVector2 b)
 | 
			
		||||
{
 | 
			
		||||
  return (MetaVector2) {
 | 
			
		||||
    .x = a.x - b.x,
 | 
			
		||||
    .y = a.y - b.y,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_line2_intersects_with (const MetaLine2 *line1,
 | 
			
		||||
                            const MetaLine2 *line2,
 | 
			
		||||
                            MetaVector2     *intersection);
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_border_is_horizontal (MetaBorder *border);
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_border_is_blocking_directions (MetaBorder               *border,
 | 
			
		||||
                                    MetaBorderMotionDirection directions);
 | 
			
		||||
 | 
			
		||||
unsigned int
 | 
			
		||||
meta_border_get_allows_directions (MetaBorder *border);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_border_set_allows_directions (MetaBorder *border, unsigned int directions);
 | 
			
		||||
 | 
			
		||||
#endif /* META_BORDER_H */
 | 
			
		||||
@@ -1477,42 +1477,11 @@ button_function_from_string (const char *str)
 | 
			
		||||
    return META_BUTTON_FUNCTION_MAXIMIZE;
 | 
			
		||||
  else if (strcmp (str, "close") == 0)
 | 
			
		||||
    return META_BUTTON_FUNCTION_CLOSE;
 | 
			
		||||
  else if (strcmp (str, "shade") == 0)
 | 
			
		||||
    return META_BUTTON_FUNCTION_SHADE;
 | 
			
		||||
  else if (strcmp (str, "above") == 0)
 | 
			
		||||
    return META_BUTTON_FUNCTION_ABOVE;
 | 
			
		||||
  else if (strcmp (str, "stick") == 0)
 | 
			
		||||
    return META_BUTTON_FUNCTION_STICK;
 | 
			
		||||
  else
 | 
			
		||||
    /* don't know; give up */
 | 
			
		||||
    return META_BUTTON_FUNCTION_LAST;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaButtonFunction
 | 
			
		||||
button_opposite_function (MetaButtonFunction ofwhat)
 | 
			
		||||
{
 | 
			
		||||
  switch (ofwhat)
 | 
			
		||||
    {
 | 
			
		||||
    case META_BUTTON_FUNCTION_SHADE:
 | 
			
		||||
      return META_BUTTON_FUNCTION_UNSHADE;
 | 
			
		||||
    case META_BUTTON_FUNCTION_UNSHADE:
 | 
			
		||||
      return META_BUTTON_FUNCTION_SHADE;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_FUNCTION_ABOVE:
 | 
			
		||||
      return META_BUTTON_FUNCTION_UNABOVE;
 | 
			
		||||
    case META_BUTTON_FUNCTION_UNABOVE:
 | 
			
		||||
      return META_BUTTON_FUNCTION_ABOVE;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_FUNCTION_STICK:
 | 
			
		||||
      return META_BUTTON_FUNCTION_UNSTICK;
 | 
			
		||||
    case META_BUTTON_FUNCTION_UNSTICK:
 | 
			
		||||
      return META_BUTTON_FUNCTION_STICK;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      return META_BUTTON_FUNCTION_LAST;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
button_layout_handler (GVariant *value,
 | 
			
		||||
                       gpointer *result,
 | 
			
		||||
@@ -1556,12 +1525,6 @@ button_layout_handler (GVariant *value,
 | 
			
		||||
          if (i > 0 && strcmp("spacer", buttons[b]) == 0)
 | 
			
		||||
            {
 | 
			
		||||
              new_layout.left_buttons_has_spacer[i-1] = TRUE;
 | 
			
		||||
              f = button_opposite_function (f);
 | 
			
		||||
 | 
			
		||||
              if (f != META_BUTTON_FUNCTION_LAST)
 | 
			
		||||
                {
 | 
			
		||||
                  new_layout.left_buttons_has_spacer[i-2] = TRUE;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
@@ -1570,11 +1533,6 @@ button_layout_handler (GVariant *value,
 | 
			
		||||
                  new_layout.left_buttons[i] = f;
 | 
			
		||||
                  used[f] = TRUE;
 | 
			
		||||
                  ++i;
 | 
			
		||||
 | 
			
		||||
                  f = button_opposite_function (f);
 | 
			
		||||
 | 
			
		||||
                  if (f != META_BUTTON_FUNCTION_LAST)
 | 
			
		||||
                      new_layout.left_buttons[i++] = f;
 | 
			
		||||
                }
 | 
			
		||||
              else
 | 
			
		||||
                {
 | 
			
		||||
@@ -1618,11 +1576,6 @@ button_layout_handler (GVariant *value,
 | 
			
		||||
          if (i > 0 && strcmp("spacer", buttons[b]) == 0)
 | 
			
		||||
            {
 | 
			
		||||
              new_layout.right_buttons_has_spacer[i-1] = TRUE;
 | 
			
		||||
              f = button_opposite_function (f);
 | 
			
		||||
              if (f != META_BUTTON_FUNCTION_LAST)
 | 
			
		||||
                {
 | 
			
		||||
                  new_layout.right_buttons_has_spacer[i-2] = TRUE;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
@@ -1631,12 +1584,6 @@ button_layout_handler (GVariant *value,
 | 
			
		||||
                  new_layout.right_buttons[i] = f;
 | 
			
		||||
                  used[f] = TRUE;
 | 
			
		||||
                  ++i;
 | 
			
		||||
 | 
			
		||||
                  f = button_opposite_function (f);
 | 
			
		||||
 | 
			
		||||
                  if (f != META_BUTTON_FUNCTION_LAST)
 | 
			
		||||
                      new_layout.right_buttons[i++] = f;
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
              else
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -85,11 +85,7 @@ struct _MetaScreen
 | 
			
		||||
  /* Cache the current monitor */
 | 
			
		||||
  int last_monitor_index;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  SnMonitorContext *sn_context;
 | 
			
		||||
  GSList *startup_sequences;
 | 
			
		||||
  guint startup_sequence_timeout;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  Window wm_cm_selection_window;
 | 
			
		||||
  guint work_area_later;
 | 
			
		||||
 
 | 
			
		||||
@@ -71,11 +71,6 @@ static void prefs_changed_callback (MetaPreference pref,
 | 
			
		||||
static void set_desktop_geometry_hint (MetaScreen *screen);
 | 
			
		||||
static void set_desktop_viewport_hint (MetaScreen *screen);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
static void meta_screen_sn_event   (SnMonitorEvent *event,
 | 
			
		||||
                                    void           *user_data);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void on_monitors_changed (MetaMonitorManager *manager,
 | 
			
		||||
                                 MetaScreen         *screen);
 | 
			
		||||
 | 
			
		||||
@@ -730,17 +725,6 @@ meta_screen_new (MetaDisplay *display,
 | 
			
		||||
 | 
			
		||||
  meta_prefs_add_listener (prefs_changed_callback, screen);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  screen->sn_context =
 | 
			
		||||
    sn_monitor_context_new (screen->display->sn_display,
 | 
			
		||||
                            screen->number,
 | 
			
		||||
                            meta_screen_sn_event,
 | 
			
		||||
                            screen,
 | 
			
		||||
                            NULL);
 | 
			
		||||
  screen->startup_sequences = NULL;
 | 
			
		||||
  screen->startup_sequence_timeout = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
 | 
			
		||||
                screen->number, screen->screen_name, screen->xroot);
 | 
			
		||||
 | 
			
		||||
@@ -800,24 +784,6 @@ meta_screen_free (MetaScreen *screen,
 | 
			
		||||
 | 
			
		||||
  meta_screen_ungrab_keys (screen);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  g_slist_foreach (screen->startup_sequences,
 | 
			
		||||
                   (GFunc) sn_startup_sequence_unref, NULL);
 | 
			
		||||
  g_slist_free (screen->startup_sequences);
 | 
			
		||||
  screen->startup_sequences = NULL;
 | 
			
		||||
 | 
			
		||||
  if (screen->startup_sequence_timeout != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_source_remove (screen->startup_sequence_timeout);
 | 
			
		||||
      screen->startup_sequence_timeout = 0;
 | 
			
		||||
    }
 | 
			
		||||
  if (screen->sn_context)
 | 
			
		||||
    {
 | 
			
		||||
      sn_monitor_context_unref (screen->sn_context);
 | 
			
		||||
      screen->sn_context = NULL;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  meta_ui_free (screen->ui);
 | 
			
		||||
 | 
			
		||||
  meta_stack_free (screen->stack);
 | 
			
		||||
@@ -2538,208 +2504,6 @@ meta_screen_unshow_desktop (MetaScreen *screen)
 | 
			
		||||
  meta_screen_update_showing_desktop_hint (screen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
static gboolean startup_sequence_timeout (void *data);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
update_startup_feedback (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  if (screen->startup_sequences != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Setting busy cursor\n");
 | 
			
		||||
      meta_screen_set_cursor (screen, META_CURSOR_BUSY);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Setting default cursor\n");
 | 
			
		||||
      meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
add_sequence (MetaScreen        *screen,
 | 
			
		||||
              SnStartupSequence *sequence)
 | 
			
		||||
{
 | 
			
		||||
  meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
              "Adding sequence %s\n",
 | 
			
		||||
              sn_startup_sequence_get_id (sequence));
 | 
			
		||||
  sn_startup_sequence_ref (sequence);
 | 
			
		||||
  screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
 | 
			
		||||
                                               sequence);
 | 
			
		||||
 | 
			
		||||
  /* our timeout just polls every second, instead of bothering
 | 
			
		||||
   * to compute exactly when we may next time out
 | 
			
		||||
   */
 | 
			
		||||
  if (screen->startup_sequence_timeout == 0)
 | 
			
		||||
    {
 | 
			
		||||
      screen->startup_sequence_timeout = g_timeout_add_seconds (1,
 | 
			
		||||
                                                                startup_sequence_timeout,
 | 
			
		||||
                                                                screen);
 | 
			
		||||
      g_source_set_name_by_id (screen->startup_sequence_timeout,
 | 
			
		||||
                               "[mutter] startup_sequence_timeout");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  update_startup_feedback (screen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
remove_sequence (MetaScreen        *screen,
 | 
			
		||||
                 SnStartupSequence *sequence)
 | 
			
		||||
{
 | 
			
		||||
  meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
              "Removing sequence %s\n",
 | 
			
		||||
              sn_startup_sequence_get_id (sequence));
 | 
			
		||||
 | 
			
		||||
  screen->startup_sequences = g_slist_remove (screen->startup_sequences,
 | 
			
		||||
                                              sequence);
 | 
			
		||||
 | 
			
		||||
  if (screen->startup_sequences == NULL &&
 | 
			
		||||
      screen->startup_sequence_timeout != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_source_remove (screen->startup_sequence_timeout);
 | 
			
		||||
      screen->startup_sequence_timeout = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  update_startup_feedback (screen);
 | 
			
		||||
 | 
			
		||||
  sn_startup_sequence_unref (sequence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GSList *list;
 | 
			
		||||
  GTimeVal now;
 | 
			
		||||
} CollectTimedOutData;
 | 
			
		||||
 | 
			
		||||
/* This should be fairly long, as it should never be required unless
 | 
			
		||||
 * apps or .desktop files are buggy, and it's confusing if
 | 
			
		||||
 * OpenOffice or whatever seems to stop launching - people
 | 
			
		||||
 * might decide they need to launch it again.
 | 
			
		||||
 */
 | 
			
		||||
#define STARTUP_TIMEOUT 15000
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
collect_timed_out_foreach (void *element,
 | 
			
		||||
                           void *data)
 | 
			
		||||
{
 | 
			
		||||
  CollectTimedOutData *ctod = data;
 | 
			
		||||
  SnStartupSequence *sequence = element;
 | 
			
		||||
  long tv_sec, tv_usec;
 | 
			
		||||
  double elapsed;
 | 
			
		||||
 | 
			
		||||
  sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
 | 
			
		||||
 | 
			
		||||
  elapsed =
 | 
			
		||||
    ((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
 | 
			
		||||
      (ctod->now.tv_usec - tv_usec))) / 1000.0;
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
              "Sequence used %g seconds vs. %g max: %s\n",
 | 
			
		||||
              elapsed, (double) STARTUP_TIMEOUT,
 | 
			
		||||
              sn_startup_sequence_get_id (sequence));
 | 
			
		||||
 | 
			
		||||
  if (elapsed > STARTUP_TIMEOUT)
 | 
			
		||||
    ctod->list = g_slist_prepend (ctod->list, sequence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
startup_sequence_timeout (void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaScreen *screen = data;
 | 
			
		||||
  CollectTimedOutData ctod;
 | 
			
		||||
  GSList *l;
 | 
			
		||||
 | 
			
		||||
  ctod.list = NULL;
 | 
			
		||||
  g_get_current_time (&ctod.now);
 | 
			
		||||
  g_slist_foreach (screen->startup_sequences,
 | 
			
		||||
                   collect_timed_out_foreach,
 | 
			
		||||
                   &ctod);
 | 
			
		||||
 | 
			
		||||
  for (l = ctod.list; l != NULL; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      SnStartupSequence *sequence = l->data;
 | 
			
		||||
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Timed out sequence %s\n",
 | 
			
		||||
                  sn_startup_sequence_get_id (sequence));
 | 
			
		||||
 | 
			
		||||
      sn_startup_sequence_complete (sequence);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_slist_free (ctod.list);
 | 
			
		||||
 | 
			
		||||
  if (screen->startup_sequences != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* remove */
 | 
			
		||||
      screen->startup_sequence_timeout = 0;
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_screen_sn_event (SnMonitorEvent *event,
 | 
			
		||||
                      void           *user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaScreen *screen;
 | 
			
		||||
  SnStartupSequence *sequence;
 | 
			
		||||
 | 
			
		||||
  screen = user_data;
 | 
			
		||||
 | 
			
		||||
  sequence = sn_monitor_event_get_startup_sequence (event);
 | 
			
		||||
 | 
			
		||||
  sn_startup_sequence_ref (sequence);
 | 
			
		||||
 | 
			
		||||
  switch (sn_monitor_event_get_type (event))
 | 
			
		||||
    {
 | 
			
		||||
    case SN_MONITOR_EVENT_INITIATED:
 | 
			
		||||
      {
 | 
			
		||||
        const char *wmclass;
 | 
			
		||||
 | 
			
		||||
        wmclass = sn_startup_sequence_get_wmclass (sequence);
 | 
			
		||||
 | 
			
		||||
        meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                    "Received startup initiated for %s wmclass %s\n",
 | 
			
		||||
                    sn_startup_sequence_get_id (sequence),
 | 
			
		||||
                    wmclass ? wmclass : "(unset)");
 | 
			
		||||
        add_sequence (screen, sequence);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case SN_MONITOR_EVENT_COMPLETED:
 | 
			
		||||
      {
 | 
			
		||||
        meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                    "Received startup completed for %s\n",
 | 
			
		||||
                    sn_startup_sequence_get_id (sequence));
 | 
			
		||||
        remove_sequence (screen,
 | 
			
		||||
                         sn_monitor_event_get_startup_sequence (event));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case SN_MONITOR_EVENT_CHANGED:
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Received startup changed for %s\n",
 | 
			
		||||
                  sn_startup_sequence_get_id (sequence));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case SN_MONITOR_EVENT_CANCELED:
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Received startup canceled for %s\n",
 | 
			
		||||
                  sn_startup_sequence_get_id (sequence));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (G_OBJECT (screen), screen_signals[STARTUP_SEQUENCE_CHANGED], 0, sequence);
 | 
			
		||||
 | 
			
		||||
  sn_startup_sequence_unref (sequence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_screen_get_startup_sequences: (skip)
 | 
			
		||||
 * @screen:
 | 
			
		||||
@@ -2751,7 +2515,6 @@ meta_screen_get_startup_sequences (MetaScreen *screen)
 | 
			
		||||
{
 | 
			
		||||
  return screen->startup_sequences;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Sets the initial_timestamp and initial_workspace properties
 | 
			
		||||
 * of a window according to information given us by the
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								src/core/startup-notification-private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/core/startup-notification-private.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
/* -*- 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
 | 
			
		||||
 *
 | 
			
		||||
 * 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, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_STARTUP_NOTIFICATION_PRIVATE_H
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_PRIVATE_H
 | 
			
		||||
 | 
			
		||||
#include "display-private.h"
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_STARTUP_NOTIFICATION (meta_startup_notification_get_type ())
 | 
			
		||||
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaStartupNotification,
 | 
			
		||||
                      meta_startup_notification,
 | 
			
		||||
                      META, STARTUP_NOTIFICATION,
 | 
			
		||||
                      GObject)
 | 
			
		||||
 | 
			
		||||
MetaStartupNotification *
 | 
			
		||||
         meta_startup_notification_get             (MetaDisplay             *display);
 | 
			
		||||
 | 
			
		||||
gboolean meta_startup_notification_handle_xevent   (MetaStartupNotification *sn,
 | 
			
		||||
                                                    XEvent                  *xevent);
 | 
			
		||||
 | 
			
		||||
void     meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
 | 
			
		||||
                                                    const gchar             *id);
 | 
			
		||||
 | 
			
		||||
GSList * meta_startup_notification_get_sequences   (MetaStartupNotification *sn);
 | 
			
		||||
 | 
			
		||||
#endif /* META_STARTUP_NOTIFICATION_PRIVATE_H */
 | 
			
		||||
							
								
								
									
										735
									
								
								src/core/startup-notification.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										735
									
								
								src/core/startup-notification.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,735 @@
 | 
			
		||||
/* -*- 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
 | 
			
		||||
 *
 | 
			
		||||
 * 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, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include <meta/errors.h>
 | 
			
		||||
#include "display-private.h"
 | 
			
		||||
#include "screen-private.h"
 | 
			
		||||
#include "startup-notification-private.h"
 | 
			
		||||
 | 
			
		||||
/* This should be fairly long, as it should never be required unless
 | 
			
		||||
 * apps or .desktop files are buggy, and it's confusing if
 | 
			
		||||
 * OpenOffice or whatever seems to stop launching - people
 | 
			
		||||
 * might decide they need to launch it again.
 | 
			
		||||
 */
 | 
			
		||||
#define STARTUP_TIMEOUT 15000000
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaStartupNotification MetaStartupNotification;
 | 
			
		||||
typedef struct _MetaStartupNotificationSequence MetaStartupNotificationSequence;
 | 
			
		||||
typedef struct _MetaStartupNotificationSequenceClass MetaStartupNotificationSequenceClass;
 | 
			
		||||
typedef struct _MetaStartupNotificationSequenceX11 MetaStartupNotificationSequenceX11;
 | 
			
		||||
typedef struct _MetaStartupNotificationSequenceX11Class MetaStartupNotificationSequenceX11Class;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PROP_SN_0,
 | 
			
		||||
  PROP_SN_DISPLAY,
 | 
			
		||||
  N_SN_PROPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PROP_SEQ_0,
 | 
			
		||||
  PROP_SEQ_ID,
 | 
			
		||||
  PROP_SEQ_TIMESTAMP,
 | 
			
		||||
  N_SEQ_PROPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  SN_CHANGED,
 | 
			
		||||
  N_SN_SIGNALS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint sn_signals[N_SN_SIGNALS];
 | 
			
		||||
static GParamSpec *sn_props[N_SN_PROPS];
 | 
			
		||||
static GParamSpec *seq_props[N_SEQ_PROPS];
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GSList *list;
 | 
			
		||||
  gint64 now;
 | 
			
		||||
} CollectTimedOutData;
 | 
			
		||||
 | 
			
		||||
struct _MetaStartupNotification
 | 
			
		||||
{
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  SnDisplay *sn_display;
 | 
			
		||||
  SnMonitorContext *sn_context;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  GSList *startup_sequences;
 | 
			
		||||
  guint startup_sequence_timeout;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaStartupNotificationSequence {
 | 
			
		||||
  GObject parent_instance;
 | 
			
		||||
  gchar *id;
 | 
			
		||||
  time_t timestamp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaStartupNotificationSequenceClass {
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
 | 
			
		||||
  void (* complete) (MetaStartupNotificationSequence *sequence);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType meta_startup_notification_get_type (void) G_GNUC_CONST;
 | 
			
		||||
GType meta_startup_notification_sequence_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE         (meta_startup_notification_sequence_get_type ())
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_SEQUENCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE, MetaStartupNotificationSequence))
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_SEQUENCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE, MetaStartupNotificationSequenceClass))
 | 
			
		||||
#define META_IS_STARTUP_NOTIFICATION_SEQUENCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE))
 | 
			
		||||
#define META_IS_STARTUP_NOTIFICATION_SEQUENCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE))
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_SEQUENCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE, MetaStartupNotificationSequenceClass))
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaStartupNotification,
 | 
			
		||||
               meta_startup_notification,
 | 
			
		||||
               G_TYPE_OBJECT)
 | 
			
		||||
G_DEFINE_TYPE (MetaStartupNotificationSequence,
 | 
			
		||||
               meta_startup_notification_sequence,
 | 
			
		||||
               G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PROP_SEQ_X11_0,
 | 
			
		||||
  PROP_SEQ_X11_SEQ,
 | 
			
		||||
  N_SEQ_X11_PROPS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaStartupNotificationSequenceX11 {
 | 
			
		||||
  MetaStartupNotificationSequence parent_instance;
 | 
			
		||||
  SnStartupSequence *seq;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaStartupNotificationSequenceX11Class {
 | 
			
		||||
  MetaStartupNotificationSequenceClass parent_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static GParamSpec *seq_x11_props[N_SEQ_X11_PROPS];
 | 
			
		||||
 | 
			
		||||
GType meta_startup_notification_sequence_x11_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11         (meta_startup_notification_sequence_x11_get_type ())
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_SEQUENCE_X11(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11, MetaStartupNotificationSequenceX11))
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_SEQUENCE_X11_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11, MetaStartupNotificationSequenceX11Class))
 | 
			
		||||
#define META_IS_STARTUP_NOTIFICATION_SEQUENCE_X11(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11))
 | 
			
		||||
#define META_IS_STARTUP_NOTIFICATION_SEQUENCE_X11_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11))
 | 
			
		||||
#define META_STARTUP_NOTIFICATION_SEQUENCE_X11_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), META_TYPE_STARTUP_NOTIFICATION_SEQUENCE_X11, MetaStartupNotificationSequenceX11Class))
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaStartupNotificationSequenceX11,
 | 
			
		||||
               meta_startup_notification_sequence_x11,
 | 
			
		||||
               META_TYPE_STARTUP_NOTIFICATION_SEQUENCE)
 | 
			
		||||
 | 
			
		||||
static void meta_startup_notification_ensure_timeout  (MetaStartupNotification *sn);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_update_feedback (MetaStartupNotification *sn)
 | 
			
		||||
{
 | 
			
		||||
  MetaScreen *screen = sn->display->screen;
 | 
			
		||||
 | 
			
		||||
  if (sn->startup_sequences != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Setting busy cursor\n");
 | 
			
		||||
      meta_screen_set_cursor (screen, META_CURSOR_BUSY);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Setting default cursor\n");
 | 
			
		||||
      meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_init (MetaStartupNotificationSequence *seq)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequence *seq;
 | 
			
		||||
 | 
			
		||||
  seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
 | 
			
		||||
  g_free (seq->id);
 | 
			
		||||
  G_OBJECT_CLASS (meta_startup_notification_sequence_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_set_property (GObject      *object,
 | 
			
		||||
                                                 guint         prop_id,
 | 
			
		||||
                                                 const GValue *value,
 | 
			
		||||
                                                 GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequence *seq;
 | 
			
		||||
 | 
			
		||||
  seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_SEQ_ID:
 | 
			
		||||
      seq->id = g_value_dup_string (value);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_SEQ_TIMESTAMP:
 | 
			
		||||
      seq->timestamp = g_value_get_int64 (value);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_get_property (GObject    *object,
 | 
			
		||||
                                                 guint       prop_id,
 | 
			
		||||
                                                 GValue     *value,
 | 
			
		||||
                                                 GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequence *seq;
 | 
			
		||||
 | 
			
		||||
  seq = META_STARTUP_NOTIFICATION_SEQUENCE (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_SEQ_ID:
 | 
			
		||||
      g_value_set_string (value, seq->id);
 | 
			
		||||
      break;
 | 
			
		||||
    case PROP_SEQ_TIMESTAMP:
 | 
			
		||||
      g_value_set_int64 (value, seq->timestamp);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_class_init (MetaStartupNotificationSequenceClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class;
 | 
			
		||||
 | 
			
		||||
  object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  object_class->finalize = meta_startup_notification_sequence_finalize;
 | 
			
		||||
  object_class->set_property = meta_startup_notification_sequence_set_property;
 | 
			
		||||
  object_class->get_property = meta_startup_notification_sequence_get_property;
 | 
			
		||||
 | 
			
		||||
  seq_props[PROP_SEQ_ID] =
 | 
			
		||||
    g_param_spec_string ("id",
 | 
			
		||||
                         "ID",
 | 
			
		||||
                         "ID",
 | 
			
		||||
                         NULL,
 | 
			
		||||
                         G_PARAM_READWRITE |
 | 
			
		||||
                         G_PARAM_CONSTRUCT_ONLY);
 | 
			
		||||
  seq_props[PROP_SEQ_TIMESTAMP] =
 | 
			
		||||
    g_param_spec_int64 ("timestamp",
 | 
			
		||||
                        "Timestamp",
 | 
			
		||||
                        "Timestamp",
 | 
			
		||||
                        G_MININT64, G_MAXINT64, 0,
 | 
			
		||||
                        G_PARAM_READWRITE |
 | 
			
		||||
                        G_PARAM_CONSTRUCT_ONLY);
 | 
			
		||||
 | 
			
		||||
  g_object_class_install_properties (object_class, N_SEQ_PROPS, seq_props);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_complete (MetaStartupNotificationSequence *seq)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequenceClass *klass;
 | 
			
		||||
 | 
			
		||||
  klass = META_STARTUP_NOTIFICATION_SEQUENCE_GET_CLASS (seq);
 | 
			
		||||
 | 
			
		||||
  if (klass->complete)
 | 
			
		||||
    klass->complete (seq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_x11_complete (MetaStartupNotificationSequence *seq)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequenceX11 *seq_x11;
 | 
			
		||||
 | 
			
		||||
  seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (seq);
 | 
			
		||||
  sn_startup_sequence_complete (seq_x11->seq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_x11_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequenceX11 *seq;
 | 
			
		||||
 | 
			
		||||
  seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
 | 
			
		||||
  sn_startup_sequence_unref (seq->seq);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_startup_notification_sequence_x11_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_x11_set_property (GObject      *object,
 | 
			
		||||
                                                     guint         prop_id,
 | 
			
		||||
                                                     const GValue *value,
 | 
			
		||||
                                                     GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequenceX11 *seq;
 | 
			
		||||
 | 
			
		||||
  seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_SEQ_X11_SEQ:
 | 
			
		||||
      seq->seq = g_value_get_pointer (value);
 | 
			
		||||
      sn_startup_sequence_ref (seq->seq);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_x11_get_property (GObject    *object,
 | 
			
		||||
                                                     guint       prop_id,
 | 
			
		||||
                                                     GValue     *value,
 | 
			
		||||
                                                     GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequenceX11 *seq;
 | 
			
		||||
 | 
			
		||||
  seq = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_SEQ_X11_SEQ:
 | 
			
		||||
      g_value_set_pointer (value, seq->seq);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_x11_init (MetaStartupNotificationSequenceX11 *seq)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sequence_x11_class_init (MetaStartupNotificationSequenceX11Class *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequenceClass *seq_class;
 | 
			
		||||
  GObjectClass *object_class;
 | 
			
		||||
 | 
			
		||||
  seq_class = META_STARTUP_NOTIFICATION_SEQUENCE_CLASS (klass);
 | 
			
		||||
  seq_class->complete = meta_startup_notification_sequence_x11_complete;
 | 
			
		||||
 | 
			
		||||
  object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
  object_class->finalize = meta_startup_notification_sequence_x11_finalize;
 | 
			
		||||
  object_class->set_property = meta_startup_notification_sequence_x11_set_property;
 | 
			
		||||
  object_class->get_property = meta_startup_notification_sequence_x11_get_property;
 | 
			
		||||
 | 
			
		||||
  seq_x11_props[PROP_SEQ_X11_SEQ] =
 | 
			
		||||
    g_param_spec_pointer ("seq",
 | 
			
		||||
                          "Sequence",
 | 
			
		||||
                          "Sequence",
 | 
			
		||||
                          G_PARAM_READWRITE |
 | 
			
		||||
                          G_PARAM_CONSTRUCT_ONLY);
 | 
			
		||||
 | 
			
		||||
  g_object_class_install_properties (object_class, N_SEQ_X11_PROPS,
 | 
			
		||||
                                     seq_x11_props);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaStartupNotificationSequence *
 | 
			
		||||
meta_startup_notification_sequence_x11_new (SnStartupSequence *seq)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (meta_startup_notification_sequence_x11_get_type (),
 | 
			
		||||
                       "id", sn_startup_sequence_get_id (seq),
 | 
			
		||||
                       "timestamp", sn_startup_sequence_get_timestamp (seq) * 1000,
 | 
			
		||||
                       "seq", seq,
 | 
			
		||||
                       NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_add_sequence_internal (MetaStartupNotification         *sn,
 | 
			
		||||
                                                 MetaStartupNotificationSequence *seq)
 | 
			
		||||
{
 | 
			
		||||
  sn->startup_sequences = g_slist_prepend (sn->startup_sequences,
 | 
			
		||||
                                           g_object_ref (seq));
 | 
			
		||||
 | 
			
		||||
  meta_startup_notification_ensure_timeout (sn);
 | 
			
		||||
  meta_startup_notification_update_feedback (sn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
collect_timed_out_foreach (void *element,
 | 
			
		||||
                           void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequence *sequence = element;
 | 
			
		||||
  CollectTimedOutData *ctod = data;
 | 
			
		||||
  gint64 elapsed;
 | 
			
		||||
 | 
			
		||||
  elapsed = ctod->now - sequence->timestamp;
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
              "Sequence used %ld ms vs. %d max: %s\n",
 | 
			
		||||
              elapsed, STARTUP_TIMEOUT, sequence->id);
 | 
			
		||||
 | 
			
		||||
  if (elapsed > STARTUP_TIMEOUT)
 | 
			
		||||
    ctod->list = g_slist_prepend (ctod->list, sequence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
startup_sequence_timeout (void *data)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotification *sn = data;
 | 
			
		||||
  CollectTimedOutData ctod;
 | 
			
		||||
  GSList *l;
 | 
			
		||||
 | 
			
		||||
  ctod.list = NULL;
 | 
			
		||||
  ctod.now = g_get_monotonic_time ();
 | 
			
		||||
  g_slist_foreach (sn->startup_sequences,
 | 
			
		||||
                   collect_timed_out_foreach,
 | 
			
		||||
                   &ctod);
 | 
			
		||||
 | 
			
		||||
  for (l = ctod.list; l != NULL; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaStartupNotificationSequence *sequence = l->data;
 | 
			
		||||
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Timed out sequence %s\n",
 | 
			
		||||
                  sequence->id);
 | 
			
		||||
 | 
			
		||||
      meta_startup_notification_sequence_complete (sequence);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_slist_free (ctod.list);
 | 
			
		||||
 | 
			
		||||
  if (sn->startup_sequences != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* remove */
 | 
			
		||||
      sn->startup_sequence_timeout = 0;
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_ensure_timeout (MetaStartupNotification *sn)
 | 
			
		||||
{
 | 
			
		||||
  if (sn->startup_sequence_timeout != 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* our timeout just polls every second, instead of bothering
 | 
			
		||||
   * to compute exactly when we may next time out
 | 
			
		||||
   */
 | 
			
		||||
  sn->startup_sequence_timeout = g_timeout_add_seconds (1,
 | 
			
		||||
                                                        startup_sequence_timeout,
 | 
			
		||||
                                                        sn);
 | 
			
		||||
  g_source_set_name_by_id (sn->startup_sequence_timeout,
 | 
			
		||||
                           "[mutter] startup_sequence_timeout");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_remove_sequence_internal (MetaStartupNotification         *sn,
 | 
			
		||||
                                                    MetaStartupNotificationSequence *seq)
 | 
			
		||||
{
 | 
			
		||||
  sn->startup_sequences = g_slist_remove (sn->startup_sequences, seq);
 | 
			
		||||
  meta_startup_notification_update_feedback (sn);
 | 
			
		||||
 | 
			
		||||
  if (sn->startup_sequences == NULL &&
 | 
			
		||||
      sn->startup_sequence_timeout != 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_source_remove (sn->startup_sequence_timeout);
 | 
			
		||||
      sn->startup_sequence_timeout = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_unref (seq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaStartupNotificationSequence *
 | 
			
		||||
meta_startup_notification_lookup_sequence (MetaStartupNotification *sn,
 | 
			
		||||
                                           const gchar             *id)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequence *seq;
 | 
			
		||||
  GSList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = sn->startup_sequences; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      seq = l->data;
 | 
			
		||||
 | 
			
		||||
      if (g_str_equal (seq->id, id))
 | 
			
		||||
        return l->data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_init (MetaStartupNotification *sn)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
 | 
			
		||||
 | 
			
		||||
  sn_monitor_context_unref (sn->sn_context);
 | 
			
		||||
  G_OBJECT_CLASS (meta_startup_notification_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_set_property (GObject      *object,
 | 
			
		||||
                                        guint         prop_id,
 | 
			
		||||
                                        const GValue *value,
 | 
			
		||||
                                        GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_SN_DISPLAY:
 | 
			
		||||
      sn->display = g_value_get_object (value);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_get_property (GObject    *object,
 | 
			
		||||
                                        guint       prop_id,
 | 
			
		||||
                                        GValue     *value,
 | 
			
		||||
                                        GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
 | 
			
		||||
 | 
			
		||||
  switch (prop_id)
 | 
			
		||||
    {
 | 
			
		||||
    case PROP_SN_DISPLAY:
 | 
			
		||||
      g_value_set_object (value, sn->display);
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
static void
 | 
			
		||||
sn_error_trap_push (SnDisplay *sn_display,
 | 
			
		||||
                    Display   *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  display = meta_display_for_x_display (xdisplay);
 | 
			
		||||
  if (display != NULL)
 | 
			
		||||
    meta_error_trap_push (display);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sn_error_trap_pop (SnDisplay *sn_display,
 | 
			
		||||
                   Display   *xdisplay)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
  display = meta_display_for_x_display (xdisplay);
 | 
			
		||||
  if (display != NULL)
 | 
			
		||||
    meta_error_trap_pop (display);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_sn_event (SnMonitorEvent *event,
 | 
			
		||||
                                    void           *user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotification *sn = user_data;
 | 
			
		||||
  MetaStartupNotificationSequence *seq;
 | 
			
		||||
  SnStartupSequence *sequence;
 | 
			
		||||
 | 
			
		||||
  sequence = sn_monitor_event_get_startup_sequence (event);
 | 
			
		||||
 | 
			
		||||
  sn_startup_sequence_ref (sequence);
 | 
			
		||||
 | 
			
		||||
  switch (sn_monitor_event_get_type (event))
 | 
			
		||||
    {
 | 
			
		||||
    case SN_MONITOR_EVENT_INITIATED:
 | 
			
		||||
      {
 | 
			
		||||
        const char *wmclass;
 | 
			
		||||
 | 
			
		||||
        wmclass = sn_startup_sequence_get_wmclass (sequence);
 | 
			
		||||
 | 
			
		||||
        meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                    "Received startup initiated for %s wmclass %s\n",
 | 
			
		||||
                    sn_startup_sequence_get_id (sequence),
 | 
			
		||||
                    wmclass ? wmclass : "(unset)");
 | 
			
		||||
 | 
			
		||||
        seq = meta_startup_notification_sequence_x11_new (sequence);
 | 
			
		||||
        meta_startup_notification_add_sequence_internal (sn, seq);
 | 
			
		||||
        g_object_unref (seq);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case SN_MONITOR_EVENT_COMPLETED:
 | 
			
		||||
      {
 | 
			
		||||
        meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                    "Received startup completed for %s\n",
 | 
			
		||||
                    sn_startup_sequence_get_id (sequence));
 | 
			
		||||
 | 
			
		||||
        meta_startup_notification_remove_sequence (sn, sn_startup_sequence_get_id (sequence));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case SN_MONITOR_EVENT_CHANGED:
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Received startup changed for %s\n",
 | 
			
		||||
                  sn_startup_sequence_get_id (sequence));
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case SN_MONITOR_EVENT_CANCELED:
 | 
			
		||||
      meta_topic (META_DEBUG_STARTUP,
 | 
			
		||||
                  "Received startup canceled for %s\n",
 | 
			
		||||
                  sn_startup_sequence_get_id (sequence));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (sn, sn_signals[SN_CHANGED], 0, sequence);
 | 
			
		||||
 | 
			
		||||
  sn_startup_sequence_unref (sequence);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_constructed (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotification *sn = META_STARTUP_NOTIFICATION (object);
 | 
			
		||||
 | 
			
		||||
  g_assert (sn->display != NULL);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  sn->sn_display = sn_display_new (sn->display->xdisplay,
 | 
			
		||||
                                   sn_error_trap_push,
 | 
			
		||||
                                   sn_error_trap_pop);
 | 
			
		||||
  sn->sn_context =
 | 
			
		||||
    sn_monitor_context_new (sn->sn_display,
 | 
			
		||||
                            sn->display->screen->number,
 | 
			
		||||
                            meta_startup_notification_sn_event,
 | 
			
		||||
                            sn,
 | 
			
		||||
                            NULL);
 | 
			
		||||
  sn->startup_sequences = NULL;
 | 
			
		||||
  sn->startup_sequence_timeout = 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_startup_notification_class_init (MetaStartupNotificationClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->constructed = meta_startup_notification_constructed;
 | 
			
		||||
  object_class->finalize = meta_startup_notification_finalize;
 | 
			
		||||
  object_class->set_property = meta_startup_notification_set_property;
 | 
			
		||||
  object_class->get_property = meta_startup_notification_get_property;
 | 
			
		||||
 | 
			
		||||
  sn_props[PROP_SN_DISPLAY] =
 | 
			
		||||
    g_param_spec_object ("display",
 | 
			
		||||
                         "Display",
 | 
			
		||||
                         "Display",
 | 
			
		||||
                         META_TYPE_DISPLAY,
 | 
			
		||||
                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 | 
			
		||||
                         G_PARAM_STATIC_STRINGS);
 | 
			
		||||
 | 
			
		||||
  sn_signals[SN_CHANGED] =
 | 
			
		||||
    g_signal_new ("changed",
 | 
			
		||||
                  META_TYPE_STARTUP_NOTIFICATION,
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0, NULL, NULL, NULL,
 | 
			
		||||
                  G_TYPE_NONE, 1, G_TYPE_POINTER);
 | 
			
		||||
 | 
			
		||||
  g_object_class_install_properties (object_class, N_SN_PROPS, sn_props);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaStartupNotification *
 | 
			
		||||
meta_startup_notification_get (MetaDisplay *display)
 | 
			
		||||
{
 | 
			
		||||
  static MetaStartupNotification *notification = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!notification)
 | 
			
		||||
    notification = g_object_new (META_TYPE_STARTUP_NOTIFICATION,
 | 
			
		||||
                                 "display", display,
 | 
			
		||||
                                 NULL);
 | 
			
		||||
 | 
			
		||||
  return notification;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_startup_notification_remove_sequence (MetaStartupNotification *sn,
 | 
			
		||||
                                           const gchar             *id)
 | 
			
		||||
{
 | 
			
		||||
  MetaStartupNotificationSequence *seq;
 | 
			
		||||
 | 
			
		||||
  seq = meta_startup_notification_lookup_sequence (sn, id);
 | 
			
		||||
  if (seq)
 | 
			
		||||
    meta_startup_notification_remove_sequence_internal (sn, seq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_startup_notification_handle_xevent (MetaStartupNotification *sn,
 | 
			
		||||
                                         XEvent                  *xevent)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  return sn_display_process_event (sn->sn_display, xevent);
 | 
			
		||||
#endif
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GSList *
 | 
			
		||||
meta_startup_notification_get_sequences (MetaStartupNotification *sn)
 | 
			
		||||
{
 | 
			
		||||
  GSList *l, *sequences = NULL;
 | 
			
		||||
 | 
			
		||||
  /* We return a list of SnStartupSequences here */
 | 
			
		||||
  for (l = sn->startup_sequences; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
      MetaStartupNotificationSequenceX11 *seq_x11;
 | 
			
		||||
 | 
			
		||||
      if (!META_IS_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      seq_x11 = META_STARTUP_NOTIFICATION_SEQUENCE_X11 (l->data);
 | 
			
		||||
      sequences = g_slist_prepend (sequences, seq_x11->seq);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return sequences;
 | 
			
		||||
}
 | 
			
		||||
@@ -1579,8 +1579,10 @@ implement_showing (MetaWindow *window,
 | 
			
		||||
       * windows we might want to know where they are on the screen,
 | 
			
		||||
       * so we should place the window even if we're hiding it rather
 | 
			
		||||
       * than showing it.
 | 
			
		||||
       * Force placing windows only when they should be already mapped,
 | 
			
		||||
       * see #751887
 | 
			
		||||
       */
 | 
			
		||||
      if (!window->placed)
 | 
			
		||||
      if (!window->placed && client_window_should_be_mapped (window))
 | 
			
		||||
        meta_window_force_placement (window);
 | 
			
		||||
 | 
			
		||||
      meta_window_hide (window);
 | 
			
		||||
@@ -3534,10 +3536,7 @@ meta_window_update_for_monitors_changed (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  const MetaMonitorInfo *old, *new;
 | 
			
		||||
 | 
			
		||||
  if (window->type == META_WINDOW_DESKTOP)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (window->override_redirect)
 | 
			
		||||
  if (window->override_redirect || window->type == META_WINDOW_DESKTOP)
 | 
			
		||||
    {
 | 
			
		||||
      meta_window_update_monitor (window, FALSE);
 | 
			
		||||
      return;
 | 
			
		||||
@@ -5303,6 +5302,11 @@ meta_window_recalc_features (MetaWindow *window)
 | 
			
		||||
 | 
			
		||||
  meta_window_recalc_skip_features (window);
 | 
			
		||||
 | 
			
		||||
  /* To prevent users from losing windows, let's prevent users from
 | 
			
		||||
   * minimizing skip-taskbar windows through the window decorations. */
 | 
			
		||||
  if (window->skip_taskbar)
 | 
			
		||||
    window->has_minimize_func = FALSE;
 | 
			
		||||
 | 
			
		||||
  meta_topic (META_DEBUG_WINDOW_OPS,
 | 
			
		||||
              "Window %s decorated = %d border_only = %d has_close = %d has_minimize = %d has_maximize = %d has_move = %d has_shade = %d skip_taskbar = %d skip_pager = %d\n",
 | 
			
		||||
              window->desc,
 | 
			
		||||
@@ -7413,14 +7417,14 @@ meta_window_set_transient_for (MetaWindow *window,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* update stacking constraints */
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_stack_update_transient (window->screen->stack, window);
 | 
			
		||||
 | 
			
		||||
  /* We know this won't create a reference cycle because we check for loops */
 | 
			
		||||
  g_clear_object (&window->transient_for);
 | 
			
		||||
  window->transient_for = parent ? g_object_ref (parent) : NULL;
 | 
			
		||||
 | 
			
		||||
  /* update stacking constraints */
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    meta_stack_update_transient (window->screen->stack, window);
 | 
			
		||||
 | 
			
		||||
  /* possibly change its group. We treat being a window's transient as
 | 
			
		||||
   * equivalent to making it your group leader, to work around shortcomings
 | 
			
		||||
   * in programs such as xmms-- see #328211.
 | 
			
		||||
@@ -7431,7 +7435,7 @@ meta_window_set_transient_for (MetaWindow *window,
 | 
			
		||||
    meta_window_group_leader_changed (window);
 | 
			
		||||
 | 
			
		||||
  if (!window->constructing && !window->override_redirect)
 | 
			
		||||
    meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 | 
			
		||||
    meta_window_queue (window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
 | 
			
		||||
 | 
			
		||||
  if (meta_window_appears_focused (window) && window->transient_for != NULL)
 | 
			
		||||
    meta_window_propagate_focus_appearance (window, TRUE);
 | 
			
		||||
@@ -7670,13 +7674,29 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
  MetaDisplay *display = window->display;
 | 
			
		||||
  gboolean unmodified;
 | 
			
		||||
  gboolean is_window_grab;
 | 
			
		||||
  ClutterModifierType grab_mods, event_mods;
 | 
			
		||||
  gfloat x, y;
 | 
			
		||||
  guint button;
 | 
			
		||||
 | 
			
		||||
  if (window->frame && meta_ui_frame_handle_event (window->frame->ui_frame, event))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (event->type != CLUTTER_BUTTON_PRESS)
 | 
			
		||||
  if (event->type != CLUTTER_BUTTON_PRESS &&
 | 
			
		||||
      event->type != CLUTTER_TOUCH_BEGIN)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (event->type == CLUTTER_TOUCH_BEGIN)
 | 
			
		||||
    {
 | 
			
		||||
      ClutterEventSequence *sequence;
 | 
			
		||||
 | 
			
		||||
      button = 1;
 | 
			
		||||
      sequence = clutter_event_get_event_sequence (event);
 | 
			
		||||
      if (!meta_display_is_pointer_emulating_sequence (window->display, sequence))
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    button = clutter_event_get_button (event);
 | 
			
		||||
 | 
			
		||||
  if (display->grab_op != META_GRAB_OP_NONE)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
@@ -7687,6 +7707,22 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
  if (window->override_redirect)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  /* Don't focus panels--they must explicitly request focus.
 | 
			
		||||
   * See bug 160470
 | 
			
		||||
   */
 | 
			
		||||
  if (window->type != META_WINDOW_DOCK)
 | 
			
		||||
    {
 | 
			
		||||
      meta_topic (META_DEBUG_FOCUS,
 | 
			
		||||
                  "Focusing %s due to button %u press (display.c)\n",
 | 
			
		||||
                  window->desc, button);
 | 
			
		||||
      meta_window_focus (window, event->any.time);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    /* However, do allow terminals to lose focus due to new
 | 
			
		||||
     * window mappings after the user clicks on a panel.
 | 
			
		||||
     */
 | 
			
		||||
    display->allow_terminal_deactivation = TRUE;
 | 
			
		||||
 | 
			
		||||
  /* We have three passive button grabs:
 | 
			
		||||
   * - on any button, without modifiers => focuses and maybe raises the window
 | 
			
		||||
   * - on resize button, with modifiers => start an interactive resizing
 | 
			
		||||
@@ -7707,9 +7743,12 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
   * care about. Just let the event through.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  ClutterModifierType grab_mods = meta_display_get_window_grab_modifiers (display);
 | 
			
		||||
  unmodified = (event->button.modifier_state & grab_mods) == 0;
 | 
			
		||||
  is_window_grab = (event->button.modifier_state & grab_mods) == grab_mods;
 | 
			
		||||
  grab_mods = meta_display_get_window_grab_modifiers (display);
 | 
			
		||||
  event_mods = clutter_event_get_state (event);
 | 
			
		||||
  unmodified = (event_mods & grab_mods) == 0;
 | 
			
		||||
  is_window_grab = (event_mods & grab_mods) == grab_mods;
 | 
			
		||||
 | 
			
		||||
  clutter_event_get_coords (event, &x, &y);
 | 
			
		||||
 | 
			
		||||
  if (unmodified)
 | 
			
		||||
    {
 | 
			
		||||
@@ -7718,27 +7757,8 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
      else
 | 
			
		||||
        meta_topic (META_DEBUG_FOCUS,
 | 
			
		||||
                    "Not raising window on click due to don't-raise-on-click option\n");
 | 
			
		||||
 | 
			
		||||
      /* Don't focus panels--they must explicitly request focus.
 | 
			
		||||
       * See bug 160470
 | 
			
		||||
       */
 | 
			
		||||
      if (window->type != META_WINDOW_DOCK)
 | 
			
		||||
        {
 | 
			
		||||
          meta_topic (META_DEBUG_FOCUS,
 | 
			
		||||
                      "Focusing %s due to unmodified button %u press (display.c)\n",
 | 
			
		||||
                      window->desc, event->button.button);
 | 
			
		||||
          meta_window_focus (window, event->any.time);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        /* However, do allow terminals to lose focus due to new
 | 
			
		||||
         * window mappings after the user clicks on a panel.
 | 
			
		||||
         */
 | 
			
		||||
        display->allow_terminal_deactivation = TRUE;
 | 
			
		||||
 | 
			
		||||
      meta_verbose ("Allowing events time %u\n",
 | 
			
		||||
                    (unsigned int)event->button.time);
 | 
			
		||||
    }
 | 
			
		||||
  else if (is_window_grab && (int) event->button.button == meta_prefs_get_mouse_button_resize ())
 | 
			
		||||
  else if (is_window_grab && (int) button == meta_prefs_get_mouse_button_resize ())
 | 
			
		||||
    {
 | 
			
		||||
      if (window->has_resize_func)
 | 
			
		||||
        {
 | 
			
		||||
@@ -7749,10 +7769,10 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
 | 
			
		||||
          meta_window_get_frame_rect (window, &frame_rect);
 | 
			
		||||
 | 
			
		||||
          west = event->button.x < (frame_rect.x + 1 * frame_rect.width / 3);
 | 
			
		||||
          east = event->button.x > (frame_rect.x + 2 * frame_rect.width / 3);
 | 
			
		||||
          north = event->button.y < (frame_rect.y + 1 * frame_rect.height / 3);
 | 
			
		||||
          south = event->button.y > (frame_rect.y + 2 * frame_rect.height / 3);
 | 
			
		||||
          west = x < (frame_rect.x + 1 * frame_rect.width / 3);
 | 
			
		||||
          east = x > (frame_rect.x + 2 * frame_rect.width / 3);
 | 
			
		||||
          north = y < (frame_rect.y + 1 * frame_rect.height / 3);
 | 
			
		||||
          south = y > (frame_rect.y + 2 * frame_rect.height / 3);
 | 
			
		||||
 | 
			
		||||
          if (west)
 | 
			
		||||
            op |= META_GRAB_OP_WINDOW_DIR_WEST;
 | 
			
		||||
@@ -7770,23 +7790,21 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
                                        op,
 | 
			
		||||
                                        TRUE,
 | 
			
		||||
                                        FALSE,
 | 
			
		||||
                                        event->button.button,
 | 
			
		||||
                                        button,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        event->any.time,
 | 
			
		||||
                                        event->button.x,
 | 
			
		||||
                                        event->button.y);
 | 
			
		||||
                                        x, y);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if (is_window_grab && (int) event->button.button == meta_prefs_get_mouse_button_menu ())
 | 
			
		||||
  else if (is_window_grab && (int) button == meta_prefs_get_mouse_button_menu ())
 | 
			
		||||
    {
 | 
			
		||||
      if (meta_prefs_get_raise_on_click ())
 | 
			
		||||
        meta_window_raise (window);
 | 
			
		||||
      meta_window_show_menu (window,
 | 
			
		||||
                             META_WINDOW_MENU_WM,
 | 
			
		||||
                             event->button.x,
 | 
			
		||||
                             event->button.y);
 | 
			
		||||
                             x, y);
 | 
			
		||||
    }
 | 
			
		||||
  else if (is_window_grab && (int) event->button.button == 1)
 | 
			
		||||
  else if (is_window_grab && (int) button == 1)
 | 
			
		||||
    {
 | 
			
		||||
      if (window->has_move_func)
 | 
			
		||||
        {
 | 
			
		||||
@@ -7796,11 +7814,10 @@ meta_window_handle_ungrabbed_event (MetaWindow         *window,
 | 
			
		||||
                                      META_GRAB_OP_MOVING,
 | 
			
		||||
                                      TRUE,
 | 
			
		||||
                                      FALSE,
 | 
			
		||||
                                      event->button.button,
 | 
			
		||||
                                      button,
 | 
			
		||||
                                      0,
 | 
			
		||||
                                      event->any.time,
 | 
			
		||||
                                      event->button.x,
 | 
			
		||||
                                      event->button.y);
 | 
			
		||||
                                      x, y);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -372,12 +372,6 @@ typedef enum
 | 
			
		||||
 * @META_BUTTON_FUNCTION_MINIMIZE: Minimize
 | 
			
		||||
 * @META_BUTTON_FUNCTION_MAXIMIZE: Maximize
 | 
			
		||||
 * @META_BUTTON_FUNCTION_CLOSE: Close
 | 
			
		||||
 * @META_BUTTON_FUNCTION_SHADE: Shade
 | 
			
		||||
 * @META_BUTTON_FUNCTION_ABOVE: Above
 | 
			
		||||
 * @META_BUTTON_FUNCTION_STICK: Stick
 | 
			
		||||
 * @META_BUTTON_FUNCTION_UNSHADE: Unshade
 | 
			
		||||
 * @META_BUTTON_FUNCTION_UNABOVE: Unabove
 | 
			
		||||
 * @META_BUTTON_FUNCTION_UNSTICK: Unstick
 | 
			
		||||
 * @META_BUTTON_FUNCTION_LAST: Marks the end of the #MetaButtonFunction enumeration
 | 
			
		||||
 *
 | 
			
		||||
 * Function a window button can have.  Note, you can't add stuff here
 | 
			
		||||
@@ -390,12 +384,6 @@ typedef enum
 | 
			
		||||
  META_BUTTON_FUNCTION_MINIMIZE,
 | 
			
		||||
  META_BUTTON_FUNCTION_MAXIMIZE,
 | 
			
		||||
  META_BUTTON_FUNCTION_CLOSE,
 | 
			
		||||
  META_BUTTON_FUNCTION_SHADE,
 | 
			
		||||
  META_BUTTON_FUNCTION_ABOVE,
 | 
			
		||||
  META_BUTTON_FUNCTION_STICK,
 | 
			
		||||
  META_BUTTON_FUNCTION_UNSHADE,
 | 
			
		||||
  META_BUTTON_FUNCTION_UNABOVE,
 | 
			
		||||
  META_BUTTON_FUNCTION_UNSTICK,
 | 
			
		||||
  META_BUTTON_FUNCTION_APPMENU,
 | 
			
		||||
  META_BUTTON_FUNCTION_LAST
 | 
			
		||||
} MetaButtonFunction;
 | 
			
		||||
@@ -405,10 +393,10 @@ typedef enum
 | 
			
		||||
/* Keep array size in sync with MAX_BUTTONS_PER_CORNER */
 | 
			
		||||
/**
 | 
			
		||||
 * MetaButtonLayout:
 | 
			
		||||
 * @left_buttons: (array fixed-size=11):
 | 
			
		||||
 * @right_buttons: (array fixed-size=11):
 | 
			
		||||
 * @left_buttons_has_spacer: (array fixed-size=11):
 | 
			
		||||
 * @right_buttons_has_spacer: (array fixed-size=11):
 | 
			
		||||
 * @left_buttons: (array fixed-size=5):
 | 
			
		||||
 * @right_buttons: (array fixed-size=5):
 | 
			
		||||
 * @left_buttons_has_spacer: (array fixed-size=5):
 | 
			
		||||
 * @right_buttons_has_spacer: (array fixed-size=5):
 | 
			
		||||
 */
 | 
			
		||||
typedef struct _MetaButtonLayout MetaButtonLayout;
 | 
			
		||||
struct _MetaButtonLayout
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@
 | 
			
		||||
    <method name="TakeControl">
 | 
			
		||||
      <arg name="force" type="b"/>
 | 
			
		||||
    </method>
 | 
			
		||||
    <method name="ReleaseControl">
 | 
			
		||||
    </method>
 | 
			
		||||
    <method name="TakeDevice">
 | 
			
		||||
      <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
 | 
			
		||||
      <arg name="major" type="u" direction="in"/>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/tests/stacking/set-parent.metatest
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/tests/stacking/set-parent.metatest
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
new_client 1 wayland
 | 
			
		||||
create 1/1
 | 
			
		||||
show 1/1
 | 
			
		||||
create 1/2
 | 
			
		||||
show 1/2
 | 
			
		||||
wait
 | 
			
		||||
assert_stacking 1/1 1/2
 | 
			
		||||
 | 
			
		||||
set_parent 1/1 2
 | 
			
		||||
wait
 | 
			
		||||
assert_stacking 1/2 1/1
 | 
			
		||||
 | 
			
		||||
local_activate 1/2
 | 
			
		||||
assert_stacking 1/2 1/1
 | 
			
		||||
@@ -41,6 +41,16 @@ lookup_window (const char *window_id)
 | 
			
		||||
  return window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_after_paint  (GdkFrameClock *clock,
 | 
			
		||||
                 GMainLoop     *loop)
 | 
			
		||||
{
 | 
			
		||||
  g_signal_handlers_disconnect_by_func (clock,
 | 
			
		||||
                                        (gpointer) on_after_paint,
 | 
			
		||||
                                        loop);
 | 
			
		||||
  g_main_loop_quit (loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
process_line (const char *line)
 | 
			
		||||
{
 | 
			
		||||
@@ -126,6 +136,31 @@ process_line (const char *line)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
  else if (strcmp (argv[0], "set_parent") == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (argc != 3)
 | 
			
		||||
        {
 | 
			
		||||
          g_print ("usage: menu <window-id> <parent-id>");
 | 
			
		||||
          goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      GtkWidget *window = lookup_window (argv[1]);
 | 
			
		||||
      if (!window)
 | 
			
		||||
        {
 | 
			
		||||
          g_print ("unknown window %s", argv[1]);
 | 
			
		||||
          goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      GtkWidget *parent_window = lookup_window (argv[2]);
 | 
			
		||||
      if (!parent_window)
 | 
			
		||||
        {
 | 
			
		||||
          g_print ("unknown parent window %s", argv[2]);
 | 
			
		||||
          goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      gtk_window_set_transient_for (GTK_WINDOW (window),
 | 
			
		||||
                                    GTK_WINDOW (parent_window));
 | 
			
		||||
    }
 | 
			
		||||
  else if (strcmp (argv[0], "show") == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (argc != 2)
 | 
			
		||||
@@ -135,10 +170,25 @@ process_line (const char *line)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      GtkWidget *window = lookup_window (argv[1]);
 | 
			
		||||
      GdkWindow *gdk_window = gtk_widget_get_window (window);
 | 
			
		||||
      if (!window)
 | 
			
		||||
        goto out;
 | 
			
		||||
 | 
			
		||||
      gtk_widget_show (window);
 | 
			
		||||
 | 
			
		||||
      /* When a Wayland client, we cannot be really sure that the window has
 | 
			
		||||
       * been mappable until after we have painted. So, in order to have the
 | 
			
		||||
       * test runner rely on the "show" command to have done what the client
 | 
			
		||||
       * needs to do in order for a window to be mappable compositor side, lets
 | 
			
		||||
       * wait with returning until after the first frame.
 | 
			
		||||
       */
 | 
			
		||||
      GdkFrameClock *frame_clock = gdk_window_get_frame_clock (gdk_window);
 | 
			
		||||
      GMainLoop *loop = g_main_loop_new (NULL, FALSE);
 | 
			
		||||
      g_signal_connect (frame_clock, "after-paint",
 | 
			
		||||
                        G_CALLBACK (on_after_paint),
 | 
			
		||||
                        loop);
 | 
			
		||||
      g_main_loop_run (loop);
 | 
			
		||||
      g_main_loop_unref (loop);
 | 
			
		||||
    }
 | 
			
		||||
  else if (strcmp (argv[0], "hide") == 0)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -767,6 +767,23 @@ test_case_do (TestCase *test,
 | 
			
		||||
                           NULL))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else if (strcmp (argv[0], "set_parent") == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if (argc != 3)
 | 
			
		||||
        BAD_COMMAND("usage: %s <client-id>/<window-id> <parent-window-id>",
 | 
			
		||||
                    argv[0]);
 | 
			
		||||
 | 
			
		||||
      TestClient *client;
 | 
			
		||||
      const char *window_id;
 | 
			
		||||
      if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
      if (!test_client_do (client, error,
 | 
			
		||||
                           "set_parent", window_id,
 | 
			
		||||
                           argv[2],
 | 
			
		||||
                           NULL))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
  else if (strcmp (argv[0], "show") == 0 ||
 | 
			
		||||
           strcmp (argv[0], "hide") == 0 ||
 | 
			
		||||
           strcmp (argv[0], "activate") == 0 ||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								src/ui/frames.c
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								src/ui/frames.c
									
									
									
									
									
								
							@@ -447,7 +447,7 @@ meta_frames_new (int screen_number)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *
 | 
			
		||||
get_theme_variant_override (MetaFrames *frames)
 | 
			
		||||
get_global_theme_variant (MetaFrames *frames)
 | 
			
		||||
{
 | 
			
		||||
  GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (frames));
 | 
			
		||||
  GtkSettings *settings = gtk_settings_get_for_screen (screen);
 | 
			
		||||
@@ -474,19 +474,15 @@ meta_ui_frame_attach_style (MetaUIFrame *frame)
 | 
			
		||||
{
 | 
			
		||||
  MetaFrames *frames = frame->frames;
 | 
			
		||||
  const char *variant;
 | 
			
		||||
  const char *variant_override;
 | 
			
		||||
 | 
			
		||||
  if (frame->style_info != NULL)
 | 
			
		||||
    meta_style_info_unref (frame->style_info);
 | 
			
		||||
 | 
			
		||||
  variant_override = get_theme_variant_override (frame->frames);
 | 
			
		||||
  variant = frame->meta_window->gtk_theme_variant;
 | 
			
		||||
  if (variant == NULL)
 | 
			
		||||
    variant = get_global_theme_variant (frame->frames);;
 | 
			
		||||
 | 
			
		||||
  if (variant_override)
 | 
			
		||||
    variant = variant_override;
 | 
			
		||||
  else
 | 
			
		||||
    variant = frame->meta_window->gtk_theme_variant;
 | 
			
		||||
 | 
			
		||||
  if (variant == NULL || strcmp(variant, "normal") == 0)
 | 
			
		||||
  if (variant == NULL || *variant == '\0')
 | 
			
		||||
    frame->style_info = meta_style_info_ref (frames->normal_style);
 | 
			
		||||
  else
 | 
			
		||||
    frame->style_info = meta_style_info_ref (meta_frames_get_theme_variant (frames,
 | 
			
		||||
@@ -970,12 +966,6 @@ meta_frame_left_click_event (MetaUIFrame *frame,
 | 
			
		||||
    case META_FRAME_CONTROL_UNMAXIMIZE:
 | 
			
		||||
    case META_FRAME_CONTROL_MINIMIZE:
 | 
			
		||||
    case META_FRAME_CONTROL_DELETE:
 | 
			
		||||
    case META_FRAME_CONTROL_SHADE:
 | 
			
		||||
    case META_FRAME_CONTROL_UNSHADE:
 | 
			
		||||
    case META_FRAME_CONTROL_ABOVE:
 | 
			
		||||
    case META_FRAME_CONTROL_UNABOVE:
 | 
			
		||||
    case META_FRAME_CONTROL_STICK:
 | 
			
		||||
    case META_FRAME_CONTROL_UNSTICK:
 | 
			
		||||
    case META_FRAME_CONTROL_MENU:
 | 
			
		||||
    case META_FRAME_CONTROL_APPMENU:
 | 
			
		||||
      frame->grab_button = event->button;
 | 
			
		||||
@@ -1074,7 +1064,10 @@ handle_button_press_event (MetaUIFrame *frame,
 | 
			
		||||
 | 
			
		||||
  control = get_control (frame, event->x, event->y);
 | 
			
		||||
 | 
			
		||||
  /* focus on click, even if click was on client area */
 | 
			
		||||
  /* don't do the rest of this if on client area */
 | 
			
		||||
  if (control == META_FRAME_CONTROL_CLIENT_AREA)
 | 
			
		||||
    return FALSE; /* not on the frame, just passed through from client */
 | 
			
		||||
 | 
			
		||||
  if (event->button == 1 &&
 | 
			
		||||
      !(control == META_FRAME_CONTROL_MINIMIZE ||
 | 
			
		||||
        control == META_FRAME_CONTROL_DELETE ||
 | 
			
		||||
@@ -1086,10 +1079,6 @@ handle_button_press_event (MetaUIFrame *frame,
 | 
			
		||||
      meta_window_focus (frame->meta_window, event->time);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* don't do the rest of this if on client area */
 | 
			
		||||
  if (control == META_FRAME_CONTROL_CLIENT_AREA)
 | 
			
		||||
    return FALSE; /* not on the frame, just passed through from client */
 | 
			
		||||
 | 
			
		||||
  /* We want to shade even if we have a GrabOp, since we'll have a move grab
 | 
			
		||||
   * if we double click the titlebar.
 | 
			
		||||
   */
 | 
			
		||||
@@ -1154,24 +1143,6 @@ handle_button_release_event (MetaUIFrame *frame,
 | 
			
		||||
        case META_FRAME_CONTROL_DELETE:
 | 
			
		||||
          meta_window_delete (frame->meta_window, event->time);
 | 
			
		||||
          break;
 | 
			
		||||
        case META_FRAME_CONTROL_SHADE:
 | 
			
		||||
          meta_window_shade (frame->meta_window, event->time);
 | 
			
		||||
          break;
 | 
			
		||||
        case META_FRAME_CONTROL_UNSHADE:
 | 
			
		||||
          meta_window_unshade (frame->meta_window, event->time);
 | 
			
		||||
          break;
 | 
			
		||||
        case META_FRAME_CONTROL_ABOVE:
 | 
			
		||||
          meta_window_make_above (frame->meta_window);
 | 
			
		||||
          break;
 | 
			
		||||
        case META_FRAME_CONTROL_UNABOVE:
 | 
			
		||||
          meta_window_unmake_above (frame->meta_window);
 | 
			
		||||
          break;
 | 
			
		||||
        case META_FRAME_CONTROL_STICK:
 | 
			
		||||
          meta_window_stick (frame->meta_window);
 | 
			
		||||
          break;
 | 
			
		||||
        case META_FRAME_CONTROL_UNSTICK:
 | 
			
		||||
          meta_window_unstick (frame->meta_window);
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -1220,18 +1191,6 @@ meta_ui_frame_update_prelit_control (MetaUIFrame     *frame,
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNMAXIMIZE:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_SHADE:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNSHADE:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_ABOVE:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNABOVE:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_STICK:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNSTICK:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_RESIZE_SE:
 | 
			
		||||
      cursor = META_CURSOR_SE_RESIZE;
 | 
			
		||||
      break;
 | 
			
		||||
@@ -1270,12 +1229,6 @@ meta_ui_frame_update_prelit_control (MetaUIFrame     *frame,
 | 
			
		||||
    case META_FRAME_CONTROL_MINIMIZE:
 | 
			
		||||
    case META_FRAME_CONTROL_MAXIMIZE:
 | 
			
		||||
    case META_FRAME_CONTROL_DELETE:
 | 
			
		||||
    case META_FRAME_CONTROL_SHADE:
 | 
			
		||||
    case META_FRAME_CONTROL_UNSHADE:
 | 
			
		||||
    case META_FRAME_CONTROL_ABOVE:
 | 
			
		||||
    case META_FRAME_CONTROL_UNABOVE:
 | 
			
		||||
    case META_FRAME_CONTROL_STICK:
 | 
			
		||||
    case META_FRAME_CONTROL_UNSTICK:
 | 
			
		||||
    case META_FRAME_CONTROL_UNMAXIMIZE:
 | 
			
		||||
      /* leave control set */
 | 
			
		||||
      break;
 | 
			
		||||
@@ -1409,6 +1362,10 @@ meta_ui_frame_get_mask (MetaUIFrame *frame,
 | 
			
		||||
                         borders.invisible.left / scale,
 | 
			
		||||
                         borders.invisible.top / scale,
 | 
			
		||||
                         frame_rect.width / scale, frame_rect.height / scale);
 | 
			
		||||
  gtk_render_background (frame->style_info->styles[META_STYLE_ELEMENT_TITLEBAR], cr,
 | 
			
		||||
                         borders.invisible.left / scale,
 | 
			
		||||
                         borders.invisible.top / scale,
 | 
			
		||||
                         frame_rect.width / scale, borders.total.top / scale);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* XXX -- this is disgusting. Find a better approach here.
 | 
			
		||||
@@ -1487,24 +1444,6 @@ meta_ui_frame_paint (MetaUIFrame  *frame,
 | 
			
		||||
    case META_FRAME_CONTROL_UNMAXIMIZE:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_MAXIMIZE;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_SHADE:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_SHADE;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNSHADE:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_UNSHADE;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_ABOVE:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_ABOVE;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNABOVE:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_UNABOVE;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_STICK:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_STICK;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNSTICK:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_UNSTICK;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_DELETE:
 | 
			
		||||
      button_type = META_BUTTON_TYPE_CLOSE;
 | 
			
		||||
      break;
 | 
			
		||||
@@ -1624,24 +1563,6 @@ control_rect (MetaFrameControl control,
 | 
			
		||||
    case META_FRAME_CONTROL_UNMAXIMIZE:
 | 
			
		||||
      rect = &fgeom->max_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_SHADE:
 | 
			
		||||
      rect = &fgeom->shade_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNSHADE:
 | 
			
		||||
      rect = &fgeom->unshade_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_ABOVE:
 | 
			
		||||
      rect = &fgeom->above_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNABOVE:
 | 
			
		||||
      rect = &fgeom->unabove_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_STICK:
 | 
			
		||||
      rect = &fgeom->stick_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_UNSTICK:
 | 
			
		||||
      rect = &fgeom->unstick_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_RESIZE_SE:
 | 
			
		||||
      break;
 | 
			
		||||
    case META_FRAME_CONTROL_RESIZE_S:
 | 
			
		||||
@@ -1726,36 +1647,6 @@ get_control (MetaUIFrame *frame, int root_x, int root_y)
 | 
			
		||||
        return META_FRAME_CONTROL_MAXIMIZE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable))
 | 
			
		||||
    {
 | 
			
		||||
      return META_FRAME_CONTROL_SHADE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable))
 | 
			
		||||
    {
 | 
			
		||||
      return META_FRAME_CONTROL_UNSHADE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable))
 | 
			
		||||
    {
 | 
			
		||||
      return META_FRAME_CONTROL_ABOVE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable))
 | 
			
		||||
    {
 | 
			
		||||
      return META_FRAME_CONTROL_UNABOVE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable))
 | 
			
		||||
    {
 | 
			
		||||
      return META_FRAME_CONTROL_STICK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable))
 | 
			
		||||
    {
 | 
			
		||||
      return META_FRAME_CONTROL_UNSTICK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* South resize always has priority over north resize,
 | 
			
		||||
   * in case of overlap.
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -39,12 +39,6 @@ typedef enum
 | 
			
		||||
  META_FRAME_CONTROL_MINIMIZE,
 | 
			
		||||
  META_FRAME_CONTROL_MAXIMIZE,
 | 
			
		||||
  META_FRAME_CONTROL_UNMAXIMIZE,
 | 
			
		||||
  META_FRAME_CONTROL_SHADE,
 | 
			
		||||
  META_FRAME_CONTROL_UNSHADE,
 | 
			
		||||
  META_FRAME_CONTROL_ABOVE,
 | 
			
		||||
  META_FRAME_CONTROL_UNABOVE,
 | 
			
		||||
  META_FRAME_CONTROL_STICK,
 | 
			
		||||
  META_FRAME_CONTROL_UNSTICK,
 | 
			
		||||
  META_FRAME_CONTROL_RESIZE_SE,
 | 
			
		||||
  META_FRAME_CONTROL_RESIZE_S,
 | 
			
		||||
  META_FRAME_CONTROL_RESIZE_SW,
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,8 @@ typedef struct _MetaFrameGeometry MetaFrameGeometry;
 | 
			
		||||
 **/
 | 
			
		||||
struct _MetaFrameLayout
 | 
			
		||||
{
 | 
			
		||||
  /** Invisible border required by the theme */
 | 
			
		||||
  GtkBorder invisible_border;
 | 
			
		||||
  /** Border/padding of the entire frame */
 | 
			
		||||
  GtkBorder frame_border;
 | 
			
		||||
  /** Border/padding of the titlebar region */
 | 
			
		||||
@@ -60,6 +62,16 @@ struct _MetaFrameLayout
 | 
			
		||||
  /** Border/padding of titlebar buttons */
 | 
			
		||||
  GtkBorder button_border;
 | 
			
		||||
 | 
			
		||||
  /** Margin of title */
 | 
			
		||||
  GtkBorder title_margin;
 | 
			
		||||
  /** Margin of titlebar buttons */
 | 
			
		||||
  GtkBorder button_margin;
 | 
			
		||||
 | 
			
		||||
  /** Min size of titlebar region */
 | 
			
		||||
  GtkRequisition titlebar_min_size;
 | 
			
		||||
  /** Min size of titlebar buttons */
 | 
			
		||||
  GtkRequisition button_min_size;
 | 
			
		||||
 | 
			
		||||
  /** Size of images in buttons */
 | 
			
		||||
  guint icon_size;
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +127,7 @@ struct _MetaFrameGeometry
 | 
			
		||||
 | 
			
		||||
  /* used for a memset hack */
 | 
			
		||||
#define ADDRESS_OF_BUTTON_RECTS(fgeom) (((char*)(fgeom)) + G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
 | 
			
		||||
#define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, unstick_rect) + sizeof (MetaButtonSpace) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
 | 
			
		||||
#define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, appmenu_rect) + sizeof (MetaButtonSpace) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
 | 
			
		||||
 | 
			
		||||
  /* The button rects (if changed adjust memset hack) */
 | 
			
		||||
  MetaButtonSpace close_rect;
 | 
			
		||||
@@ -123,12 +135,6 @@ struct _MetaFrameGeometry
 | 
			
		||||
  MetaButtonSpace min_rect;
 | 
			
		||||
  MetaButtonSpace menu_rect;
 | 
			
		||||
  MetaButtonSpace appmenu_rect;
 | 
			
		||||
  MetaButtonSpace shade_rect;
 | 
			
		||||
  MetaButtonSpace above_rect;
 | 
			
		||||
  MetaButtonSpace stick_rect;
 | 
			
		||||
  MetaButtonSpace unshade_rect;
 | 
			
		||||
  MetaButtonSpace unabove_rect;
 | 
			
		||||
  MetaButtonSpace unstick_rect;
 | 
			
		||||
  /* End of button rects (if changed adjust memset hack) */
 | 
			
		||||
 | 
			
		||||
  /* Saved button layout */
 | 
			
		||||
@@ -158,17 +164,12 @@ typedef enum
 | 
			
		||||
  META_BUTTON_TYPE_MINIMIZE,
 | 
			
		||||
  META_BUTTON_TYPE_MENU,
 | 
			
		||||
  META_BUTTON_TYPE_APPMENU,
 | 
			
		||||
  META_BUTTON_TYPE_SHADE,
 | 
			
		||||
  META_BUTTON_TYPE_ABOVE,
 | 
			
		||||
  META_BUTTON_TYPE_STICK,
 | 
			
		||||
  META_BUTTON_TYPE_UNSHADE,
 | 
			
		||||
  META_BUTTON_TYPE_UNABOVE,
 | 
			
		||||
  META_BUTTON_TYPE_UNSTICK,
 | 
			
		||||
  META_BUTTON_TYPE_LAST
 | 
			
		||||
} MetaButtonType;
 | 
			
		||||
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  META_STYLE_ELEMENT_WINDOW,
 | 
			
		||||
  META_STYLE_ELEMENT_FRAME,
 | 
			
		||||
  META_STYLE_ELEMENT_TITLEBAR,
 | 
			
		||||
  META_STYLE_ELEMENT_TITLE,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								src/ui/theme.c
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								src/ui/theme.c
									
									
									
									
									
								
							@@ -79,10 +79,14 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
 | 
			
		||||
 | 
			
		||||
  if (!layout->has_title)
 | 
			
		||||
    text_height = 0;
 | 
			
		||||
  else
 | 
			
		||||
    text_height = layout->title_margin.top + text_height + layout->title_margin.bottom;
 | 
			
		||||
 | 
			
		||||
  buttons_height = layout->icon_size +
 | 
			
		||||
    layout->button_border.top + layout->button_border.bottom;
 | 
			
		||||
  content_height = MAX (buttons_height, text_height) +
 | 
			
		||||
  buttons_height = MAX ((int)layout->icon_size, layout->button_min_size.height) +
 | 
			
		||||
    layout->button_margin.top + layout->button_border.top +
 | 
			
		||||
    layout->button_margin.bottom + layout->button_border.bottom;
 | 
			
		||||
  content_height = MAX (buttons_height, text_height);
 | 
			
		||||
  content_height = MAX (content_height, layout->titlebar_min_size.height) +
 | 
			
		||||
                   layout->titlebar_border.top + layout->titlebar_border.bottom;
 | 
			
		||||
 | 
			
		||||
  borders->visible.top    = layout->frame_border.top + content_height;
 | 
			
		||||
@@ -90,23 +94,28 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
 | 
			
		||||
  borders->visible.right  = layout->frame_border.right;
 | 
			
		||||
  borders->visible.bottom = layout->frame_border.bottom;
 | 
			
		||||
 | 
			
		||||
  borders->invisible = layout->invisible_border;
 | 
			
		||||
 | 
			
		||||
  draggable_borders = meta_prefs_get_draggable_border_width ();
 | 
			
		||||
 | 
			
		||||
  if (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE)
 | 
			
		||||
    {
 | 
			
		||||
      borders->invisible.left   = MAX (0, draggable_borders - borders->visible.left);
 | 
			
		||||
      borders->invisible.right  = MAX (0, draggable_borders - borders->visible.right);
 | 
			
		||||
      borders->invisible.left   = MAX (borders->invisible.left,
 | 
			
		||||
                                       draggable_borders - borders->visible.left);
 | 
			
		||||
      borders->invisible.right  = MAX (borders->invisible.right,
 | 
			
		||||
                                       draggable_borders - borders->visible.right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE)
 | 
			
		||||
    {
 | 
			
		||||
      borders->invisible.bottom = MAX (0, draggable_borders - borders->visible.bottom);
 | 
			
		||||
      borders->invisible.bottom = MAX (borders->invisible.bottom,
 | 
			
		||||
                                       draggable_borders - borders->visible.bottom);
 | 
			
		||||
 | 
			
		||||
      /* borders.visible.top is the height of the *title bar*. We can't do the same
 | 
			
		||||
       * algorithm here, titlebars are expectedly much bigger. Just subtract a couple
 | 
			
		||||
       * pixels to get a proper feel. */
 | 
			
		||||
      if (type != META_FRAME_TYPE_ATTACHED)
 | 
			
		||||
        borders->invisible.top    = MAX (0, draggable_borders - 2);
 | 
			
		||||
        borders->invisible.top    = MAX (borders->invisible.top, draggable_borders - 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  borders->total.left   = borders->invisible.left   + borders->visible.left;
 | 
			
		||||
@@ -177,17 +186,6 @@ rect_for_function (MetaFrameGeometry *fgeom,
 | 
			
		||||
        return &fgeom->close_rect;
 | 
			
		||||
      else
 | 
			
		||||
        return NULL;
 | 
			
		||||
    case META_BUTTON_FUNCTION_STICK:
 | 
			
		||||
    case META_BUTTON_FUNCTION_SHADE:
 | 
			
		||||
    case META_BUTTON_FUNCTION_ABOVE:
 | 
			
		||||
    case META_BUTTON_FUNCTION_UNSTICK:
 | 
			
		||||
    case META_BUTTON_FUNCTION_UNSHADE:
 | 
			
		||||
    case META_BUTTON_FUNCTION_UNABOVE:
 | 
			
		||||
      /* Fringe buttons that used to be supported by theme versions >v1;
 | 
			
		||||
       * if we want to support them again, we need to return the
 | 
			
		||||
       * correspondings rects here
 | 
			
		||||
       */
 | 
			
		||||
      return NULL;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_FUNCTION_LAST:
 | 
			
		||||
      return NULL;
 | 
			
		||||
@@ -245,6 +243,16 @@ get_padding_and_border (GtkStyleContext *style,
 | 
			
		||||
  border->bottom += tmp.bottom;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
get_min_size (GtkStyleContext *style,
 | 
			
		||||
              GtkRequisition  *requisition)
 | 
			
		||||
{
 | 
			
		||||
  gtk_style_context_get (style, gtk_style_context_get_state (style),
 | 
			
		||||
                         "min-width", &requisition->width,
 | 
			
		||||
                         "min-height", &requisition->height,
 | 
			
		||||
                         NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
scale_border (GtkBorder *border,
 | 
			
		||||
              double     factor)
 | 
			
		||||
@@ -262,6 +270,8 @@ meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
 | 
			
		||||
{
 | 
			
		||||
  GtkStyleContext *style;
 | 
			
		||||
  GtkBorder border;
 | 
			
		||||
  GtkRequisition requisition;
 | 
			
		||||
  GdkRectangle clip_rect;
 | 
			
		||||
  int border_radius, max_radius;
 | 
			
		||||
 | 
			
		||||
  meta_style_info_set_flags (style_info, flags);
 | 
			
		||||
@@ -270,6 +280,12 @@ meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
 | 
			
		||||
  get_padding_and_border (style, &layout->frame_border);
 | 
			
		||||
  scale_border (&layout->frame_border, layout->title_scale);
 | 
			
		||||
 | 
			
		||||
  gtk_render_background_get_clip (style, 0, 0, 0, 0, &clip_rect);
 | 
			
		||||
  layout->invisible_border.left = -clip_rect.x;
 | 
			
		||||
  layout->invisible_border.right = clip_rect.width + clip_rect.x;
 | 
			
		||||
  layout->invisible_border.top = -clip_rect.y;
 | 
			
		||||
  layout->invisible_border.bottom = clip_rect.height + clip_rect.y;
 | 
			
		||||
 | 
			
		||||
  if (layout->hide_buttons)
 | 
			
		||||
    layout->icon_size = 0;
 | 
			
		||||
 | 
			
		||||
@@ -292,14 +308,25 @@ meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
 | 
			
		||||
  max_radius = MIN (layout->frame_border.bottom, layout->frame_border.right);
 | 
			
		||||
  layout->bottom_right_corner_rounded_radius = MAX (border_radius, max_radius);
 | 
			
		||||
 | 
			
		||||
  get_min_size (style, &layout->titlebar_min_size);
 | 
			
		||||
  get_padding_and_border (style, &layout->titlebar_border);
 | 
			
		||||
  scale_border (&layout->titlebar_border, layout->title_scale);
 | 
			
		||||
 | 
			
		||||
  style = style_info->styles[META_STYLE_ELEMENT_TITLE];
 | 
			
		||||
  gtk_style_context_get_margin (style, gtk_style_context_get_state (style),
 | 
			
		||||
                                &layout->title_margin);
 | 
			
		||||
  scale_border (&layout->title_margin, layout->title_scale);
 | 
			
		||||
 | 
			
		||||
  style = style_info->styles[META_STYLE_ELEMENT_BUTTON];
 | 
			
		||||
  get_min_size (style, &layout->button_min_size);
 | 
			
		||||
  get_padding_and_border (style, &layout->button_border);
 | 
			
		||||
  scale_border (&layout->button_border, layout->title_scale);
 | 
			
		||||
  gtk_style_context_get_margin (style, gtk_style_context_get_state (style),
 | 
			
		||||
                                &layout->button_margin);
 | 
			
		||||
  scale_border (&layout->button_margin, layout->title_scale);
 | 
			
		||||
 | 
			
		||||
  style = style_info->styles[META_STYLE_ELEMENT_IMAGE];
 | 
			
		||||
  get_min_size (style, &requisition);
 | 
			
		||||
  get_padding_and_border (style, &border);
 | 
			
		||||
  scale_border (&border, layout->title_scale);
 | 
			
		||||
 | 
			
		||||
@@ -307,6 +334,18 @@ meta_frame_layout_sync_with_style (MetaFrameLayout *layout,
 | 
			
		||||
  layout->button_border.right += border.right;
 | 
			
		||||
  layout->button_border.top += border.top;
 | 
			
		||||
  layout->button_border.bottom += border.bottom;
 | 
			
		||||
 | 
			
		||||
  gtk_style_context_get_margin (style, gtk_style_context_get_state (style),
 | 
			
		||||
                                &border);
 | 
			
		||||
  layout->button_border.left += border.left;
 | 
			
		||||
  layout->button_border.right += border.right;
 | 
			
		||||
  layout->button_border.top += border.top;
 | 
			
		||||
  layout->button_border.bottom += border.bottom;
 | 
			
		||||
 | 
			
		||||
  layout->button_min_size.width = MAX(layout->button_min_size.width,
 | 
			
		||||
                                      requisition.width);
 | 
			
		||||
  layout->button_min_size.height = MAX(layout->button_min_size.height,
 | 
			
		||||
                                       requisition.height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -370,9 +409,9 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
                  (fgeom->content_border.right + borders.invisible.right);
 | 
			
		||||
  content_height = borders.visible.top - fgeom->content_border.top - fgeom->content_border.bottom;
 | 
			
		||||
 | 
			
		||||
  button_width = layout->icon_size +
 | 
			
		||||
  button_width = MAX ((int)layout->icon_size, layout->button_min_size.width) +
 | 
			
		||||
                 layout->button_border.left + layout->button_border.right;
 | 
			
		||||
  button_height = layout->icon_size +
 | 
			
		||||
  button_height = MAX ((int)layout->icon_size, layout->button_min_size.height) +
 | 
			
		||||
                  layout->button_border.top + layout->button_border.bottom;
 | 
			
		||||
  button_width *= scale;
 | 
			
		||||
  button_height *= scale;
 | 
			
		||||
@@ -433,11 +472,15 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
 | 
			
		||||
      space_used_by_buttons = 0;
 | 
			
		||||
 | 
			
		||||
      space_used_by_buttons += layout->button_margin.left * scale * n_left;
 | 
			
		||||
      space_used_by_buttons += button_width * n_left;
 | 
			
		||||
      space_used_by_buttons += layout->button_margin.right * scale * n_left;
 | 
			
		||||
      space_used_by_buttons += (button_width * 0.75) * n_left_spacers;
 | 
			
		||||
      space_used_by_buttons += layout->titlebar_spacing * scale * MAX (n_left - 1, 0);
 | 
			
		||||
 | 
			
		||||
      space_used_by_buttons += layout->button_margin.left * scale * n_right;
 | 
			
		||||
      space_used_by_buttons += button_width * n_right;
 | 
			
		||||
      space_used_by_buttons += layout->button_margin.right * scale * n_right;
 | 
			
		||||
      space_used_by_buttons += (button_width * 0.75) * n_right_spacers;
 | 
			
		||||
      space_used_by_buttons += layout->titlebar_spacing * scale * MAX (n_right - 1, 0);
 | 
			
		||||
 | 
			
		||||
@@ -457,22 +500,10 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Otherwise we need to shave out a button. Shave
 | 
			
		||||
       * above, stick, shade, min, max, close, then menu (menu is most useful);
 | 
			
		||||
       * min, max, close, then menu (menu is most useful);
 | 
			
		||||
       * prefer the default button locations.
 | 
			
		||||
       */
 | 
			
		||||
      if (strip_button (left_func_rects, &n_left, &fgeom->above_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (right_func_rects, &n_right, &fgeom->above_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (left_func_rects, &n_left, &fgeom->stick_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (right_func_rects, &n_right, &fgeom->stick_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (left_func_rects, &n_left, &fgeom->shade_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (right_func_rects, &n_right, &fgeom->shade_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (left_func_rects, &n_left, &fgeom->min_rect))
 | 
			
		||||
      if (strip_button (left_func_rects, &n_left, &fgeom->min_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
      else if (strip_button (right_func_rects, &n_right, &fgeom->min_rect))
 | 
			
		||||
        continue;
 | 
			
		||||
@@ -519,6 +550,8 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
      if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      x -= layout->button_margin.right * scale;
 | 
			
		||||
 | 
			
		||||
      rect = right_func_rects[i];
 | 
			
		||||
      rect->visible.x = x - button_width;
 | 
			
		||||
      if (right_buttons_has_spacer[i])
 | 
			
		||||
@@ -544,7 +577,7 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
      else
 | 
			
		||||
        g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
 | 
			
		||||
 | 
			
		||||
      x = rect->visible.x;
 | 
			
		||||
      x = rect->visible.x - layout->button_margin.left * scale;
 | 
			
		||||
 | 
			
		||||
      if (i > 0)
 | 
			
		||||
        x -= layout->titlebar_spacing;
 | 
			
		||||
@@ -563,6 +596,8 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
    {
 | 
			
		||||
      MetaButtonSpace *rect;
 | 
			
		||||
 | 
			
		||||
      x += layout->button_margin.left * scale;
 | 
			
		||||
 | 
			
		||||
      rect = left_func_rects[i];
 | 
			
		||||
 | 
			
		||||
      rect->visible.x = x;
 | 
			
		||||
@@ -589,7 +624,7 @@ meta_frame_layout_calc_geometry (MetaFrameLayout        *layout,
 | 
			
		||||
      else
 | 
			
		||||
        g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
 | 
			
		||||
 | 
			
		||||
      x = rect->visible.x + rect->visible.width;
 | 
			
		||||
      x = rect->visible.x + rect->visible.width + layout->button_margin.right * scale;
 | 
			
		||||
      if (i < n_left - 1)
 | 
			
		||||
        x += layout->titlebar_spacing * scale;
 | 
			
		||||
      if (left_buttons_has_spacer[i])
 | 
			
		||||
@@ -643,30 +678,6 @@ get_button_rect (MetaButtonType           type,
 | 
			
		||||
      *rect = fgeom->close_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_SHADE:
 | 
			
		||||
      *rect = fgeom->shade_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_UNSHADE:
 | 
			
		||||
      *rect = fgeom->unshade_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_ABOVE:
 | 
			
		||||
      *rect = fgeom->above_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_UNABOVE:
 | 
			
		||||
      *rect = fgeom->unabove_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_STICK:
 | 
			
		||||
      *rect = fgeom->stick_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_UNSTICK:
 | 
			
		||||
      *rect = fgeom->unstick_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case META_BUTTON_TYPE_MAXIMIZE:
 | 
			
		||||
      *rect = fgeom->max_rect.visible;
 | 
			
		||||
      break;
 | 
			
		||||
@@ -890,6 +901,7 @@ meta_frame_layout_draw_with_style (MetaFrameLayout         *layout,
 | 
			
		||||
      cairo_restore (cr);
 | 
			
		||||
      if (button_class)
 | 
			
		||||
        gtk_style_context_remove_class (style, button_class);
 | 
			
		||||
      gtk_style_context_set_state (style, state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -975,6 +987,7 @@ static GtkStyleContext *
 | 
			
		||||
create_style_context (GType            widget_type,
 | 
			
		||||
                      GtkStyleContext *parent_style,
 | 
			
		||||
                      GtkCssProvider  *provider,
 | 
			
		||||
                      const char      *object_name,
 | 
			
		||||
                      const char      *first_class,
 | 
			
		||||
                      ...)
 | 
			
		||||
{
 | 
			
		||||
@@ -994,6 +1007,9 @@ create_style_context (GType            widget_type,
 | 
			
		||||
 | 
			
		||||
  gtk_widget_path_append_type (path, widget_type);
 | 
			
		||||
 | 
			
		||||
  if (object_name)
 | 
			
		||||
    gtk_widget_path_iter_set_object_name (path, -1, object_name);
 | 
			
		||||
 | 
			
		||||
  va_start (ap, first_class);
 | 
			
		||||
  for (name = first_class; name; name = va_arg (ap, const char *))
 | 
			
		||||
    gtk_widget_path_iter_add_class (path, -1, name);
 | 
			
		||||
@@ -1029,40 +1045,48 @@ meta_theme_create_style_info (GdkScreen   *screen,
 | 
			
		||||
  style_info = g_new0 (MetaStyleInfo, 1);
 | 
			
		||||
  style_info->refcount = 1;
 | 
			
		||||
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_FRAME] =
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_WINDOW] =
 | 
			
		||||
    create_style_context (META_TYPE_FRAMES,
 | 
			
		||||
                          NULL,
 | 
			
		||||
                          provider,
 | 
			
		||||
                          "window",
 | 
			
		||||
                          GTK_STYLE_CLASS_BACKGROUND,
 | 
			
		||||
                          "window-frame",
 | 
			
		||||
                          "ssd",
 | 
			
		||||
                          NULL);
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_FRAME] =
 | 
			
		||||
    create_style_context (META_TYPE_FRAMES,
 | 
			
		||||
                          style_info->styles[META_STYLE_ELEMENT_WINDOW],
 | 
			
		||||
                          provider,
 | 
			
		||||
                          "decoration",
 | 
			
		||||
                          NULL);
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_TITLEBAR] =
 | 
			
		||||
    create_style_context (GTK_TYPE_HEADER_BAR,
 | 
			
		||||
                          style_info->styles[META_STYLE_ELEMENT_FRAME],
 | 
			
		||||
                          provider,
 | 
			
		||||
                          "headerbar",
 | 
			
		||||
                          GTK_STYLE_CLASS_TITLEBAR,
 | 
			
		||||
                          GTK_STYLE_CLASS_HORIZONTAL,
 | 
			
		||||
                          "default-decoration",
 | 
			
		||||
                          "header-bar",
 | 
			
		||||
                          NULL);
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_TITLE] =
 | 
			
		||||
    create_style_context (GTK_TYPE_LABEL,
 | 
			
		||||
                          style_info->styles[META_STYLE_ELEMENT_TITLEBAR],
 | 
			
		||||
                          provider,
 | 
			
		||||
                          "label",
 | 
			
		||||
                          GTK_STYLE_CLASS_TITLE,
 | 
			
		||||
                          NULL);
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_BUTTON] =
 | 
			
		||||
    create_style_context (GTK_TYPE_BUTTON,
 | 
			
		||||
                          style_info->styles[META_STYLE_ELEMENT_TITLEBAR],
 | 
			
		||||
                          provider,
 | 
			
		||||
                          GTK_STYLE_CLASS_BUTTON,
 | 
			
		||||
                          "button",
 | 
			
		||||
                          "titlebutton",
 | 
			
		||||
                          NULL);
 | 
			
		||||
  style_info->styles[META_STYLE_ELEMENT_IMAGE] =
 | 
			
		||||
    create_style_context (GTK_TYPE_IMAGE,
 | 
			
		||||
                          style_info->styles[META_STYLE_ELEMENT_BUTTON],
 | 
			
		||||
                          provider,
 | 
			
		||||
                          "image",
 | 
			
		||||
                          NULL);
 | 
			
		||||
  return style_info;
 | 
			
		||||
}
 | 
			
		||||
@@ -1169,9 +1193,10 @@ meta_style_info_create_font_desc (MetaStyleInfo *style_info)
 | 
			
		||||
{
 | 
			
		||||
  PangoFontDescription *font_desc;
 | 
			
		||||
  const PangoFontDescription *override = meta_prefs_get_titlebar_font ();
 | 
			
		||||
  GtkStyleContext *context = style_info->styles[META_STYLE_ELEMENT_TITLE];
 | 
			
		||||
 | 
			
		||||
  gtk_style_context_get (style_info->styles[META_STYLE_ELEMENT_TITLE],
 | 
			
		||||
                         GTK_STATE_FLAG_NORMAL,
 | 
			
		||||
  gtk_style_context_get (context,
 | 
			
		||||
                         gtk_style_context_get_state (context),
 | 
			
		||||
                         "font", &font_desc, NULL);
 | 
			
		||||
 | 
			
		||||
  if (override)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										707
									
								
								src/wayland/meta-pointer-confinement-wayland.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										707
									
								
								src/wayland/meta-pointer-confinement-wayland.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,707 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "wayland/meta-pointer-confinement-wayland.h"
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include <cairo.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "core/meta-border.h"
 | 
			
		||||
#include "wayland/meta-wayland-seat.h"
 | 
			
		||||
#include "wayland/meta-wayland-pointer.h"
 | 
			
		||||
#include "wayland/meta-wayland-pointer-constraints.h"
 | 
			
		||||
#include "wayland/meta-wayland-surface.h"
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
#include "compositor/meta-surface-actor-wayland.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaPointerConfinementWayland
 | 
			
		||||
{
 | 
			
		||||
  MetaPointerConstraint parent;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaBox
 | 
			
		||||
{
 | 
			
		||||
  int x1;
 | 
			
		||||
  int y1;
 | 
			
		||||
  int x2;
 | 
			
		||||
  int y2;
 | 
			
		||||
} MetaBox;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland,
 | 
			
		||||
               META_TYPE_POINTER_CONSTRAINT);
 | 
			
		||||
 | 
			
		||||
static MetaBorder *
 | 
			
		||||
add_border (GArray *borders,
 | 
			
		||||
            float x1, float y1,
 | 
			
		||||
            float x2, float y2,
 | 
			
		||||
            MetaBorderMotionDirection blocking_directions)
 | 
			
		||||
{
 | 
			
		||||
  MetaBorder border;
 | 
			
		||||
 | 
			
		||||
  border = (MetaBorder) {
 | 
			
		||||
    .line = (MetaLine2) {
 | 
			
		||||
      .a = (MetaVector2) {
 | 
			
		||||
        .x = x1,
 | 
			
		||||
        .y = y1,
 | 
			
		||||
      },
 | 
			
		||||
      .b = (MetaVector2) {
 | 
			
		||||
        .x = x2,
 | 
			
		||||
        .y = y2,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    .blocking_directions = blocking_directions,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  g_array_append_val (borders, border);
 | 
			
		||||
 | 
			
		||||
  return &g_array_index (borders, MetaBorder, borders->len - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gint
 | 
			
		||||
compare_lines_x (gconstpointer a, gconstpointer b)
 | 
			
		||||
{
 | 
			
		||||
  const MetaBorder *border_a = a;
 | 
			
		||||
  const MetaBorder *border_b = b;
 | 
			
		||||
 | 
			
		||||
  if (border_a->line.a.x == border_b->line.a.x)
 | 
			
		||||
    return border_a->line.b.x < border_b->line.b.x;
 | 
			
		||||
  else
 | 
			
		||||
    return border_a->line.a.x > border_b->line.a.x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
add_non_overlapping_edges (MetaBox     *boxes,
 | 
			
		||||
                           unsigned int band_above_start,
 | 
			
		||||
                           unsigned int band_below_start,
 | 
			
		||||
                           unsigned int band_below_end,
 | 
			
		||||
                           GArray      *borders)
 | 
			
		||||
{
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
  GArray *band_merge;
 | 
			
		||||
  MetaBorder *border;
 | 
			
		||||
  MetaBorder *prev_border;
 | 
			
		||||
  MetaBorder *new_border;
 | 
			
		||||
 | 
			
		||||
  band_merge = g_array_new (FALSE, FALSE, sizeof *border);
 | 
			
		||||
 | 
			
		||||
  /* Add bottom band of previous row, and top band of current row, and
 | 
			
		||||
   * sort them so lower left x coordinate comes first. If there are two
 | 
			
		||||
   * borders with the same left x coordinate, the wider one comes first.
 | 
			
		||||
   */
 | 
			
		||||
  for (i = band_above_start; i < band_below_start; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaBox *box = &boxes[i];
 | 
			
		||||
      add_border (band_merge, box->x1, box->y2, box->x2, box->y2,
 | 
			
		||||
                  META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
 | 
			
		||||
    }
 | 
			
		||||
  for (i = band_below_start; i < band_below_end; i++)
 | 
			
		||||
    {
 | 
			
		||||
      MetaBox *box= &boxes[i];
 | 
			
		||||
      add_border (band_merge, box->x1, box->y1, box->x2, box->y1,
 | 
			
		||||
                  META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
 | 
			
		||||
    }
 | 
			
		||||
  g_array_sort (band_merge, compare_lines_x);
 | 
			
		||||
 | 
			
		||||
  /* Combine the two combined bands so that any overlapping border is
 | 
			
		||||
   * eliminated. */
 | 
			
		||||
  prev_border = NULL;
 | 
			
		||||
  for (i = 0; i < band_merge->len; i++)
 | 
			
		||||
    {
 | 
			
		||||
      border = &g_array_index (band_merge, MetaBorder, i);
 | 
			
		||||
 | 
			
		||||
      g_assert (border->line.a.y == border->line.b.y);
 | 
			
		||||
      g_assert (!prev_border ||
 | 
			
		||||
                prev_border->line.a.y == border->line.a.y);
 | 
			
		||||
      g_assert (!prev_border ||
 | 
			
		||||
                (prev_border->line.a.x != border->line.a.x ||
 | 
			
		||||
                 prev_border->line.b.x != border->line.b.x));
 | 
			
		||||
      g_assert (!prev_border ||
 | 
			
		||||
                prev_border->line.a.x <= border->line.a.x);
 | 
			
		||||
 | 
			
		||||
      if (prev_border &&
 | 
			
		||||
          prev_border->line.a.x == border->line.a.x)
 | 
			
		||||
        {
 | 
			
		||||
          /*
 | 
			
		||||
           * ------------ +
 | 
			
		||||
           * -------      =
 | 
			
		||||
           * [     ]-----
 | 
			
		||||
           */
 | 
			
		||||
          prev_border->line.a.x = border->line.b.x;
 | 
			
		||||
        }
 | 
			
		||||
      else if (prev_border &&
 | 
			
		||||
               prev_border->line.b.x == border->line.b.x)
 | 
			
		||||
        {
 | 
			
		||||
          /*
 | 
			
		||||
           * ------------ +
 | 
			
		||||
           *       ------ =
 | 
			
		||||
           * ------[    ]
 | 
			
		||||
           */
 | 
			
		||||
          prev_border->line.b.x = border->line.a.x;
 | 
			
		||||
        }
 | 
			
		||||
      else if (prev_border &&
 | 
			
		||||
               prev_border->line.b.x == border->line.a.x)
 | 
			
		||||
        {
 | 
			
		||||
          /*
 | 
			
		||||
           * --------        +
 | 
			
		||||
           *         ------  =
 | 
			
		||||
           * --------------
 | 
			
		||||
           */
 | 
			
		||||
          prev_border->line.b.x = border->line.b.x;
 | 
			
		||||
        }
 | 
			
		||||
      else if (prev_border &&
 | 
			
		||||
               prev_border->line.b.x >= border->line.a.x)
 | 
			
		||||
        {
 | 
			
		||||
          /*
 | 
			
		||||
           * --------------- +
 | 
			
		||||
           *      ------     =
 | 
			
		||||
           * -----[    ]----
 | 
			
		||||
           */
 | 
			
		||||
          new_border = add_border (borders,
 | 
			
		||||
                                   border->line.b.x,
 | 
			
		||||
                                   border->line.b.y,
 | 
			
		||||
                                   prev_border->line.b.x,
 | 
			
		||||
                                   prev_border->line.b.y,
 | 
			
		||||
                                   prev_border->blocking_directions);
 | 
			
		||||
          prev_border->line.b.x = border->line.a.x;
 | 
			
		||||
          prev_border = new_border;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          g_assert (!prev_border ||
 | 
			
		||||
                    prev_border->line.b.x < border->line.a.x);
 | 
			
		||||
          /*
 | 
			
		||||
           * First border or non-overlapping.
 | 
			
		||||
           *
 | 
			
		||||
           * -----           +
 | 
			
		||||
           *        -----    =
 | 
			
		||||
           * -----  -----
 | 
			
		||||
           */
 | 
			
		||||
          g_array_append_val (borders, *border);
 | 
			
		||||
          prev_border = &g_array_index (borders, MetaBorder, borders->len - 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_array_free (band_merge, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
add_band_bottom_edges (MetaBox *boxes,
 | 
			
		||||
                       int      band_start,
 | 
			
		||||
                       int      band_end,
 | 
			
		||||
                       GArray  *borders)
 | 
			
		||||
{
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  for (i = band_start; i < band_end; i++)
 | 
			
		||||
    {
 | 
			
		||||
      add_border (borders,
 | 
			
		||||
                  boxes[i].x1, boxes[i].y2,
 | 
			
		||||
                  boxes[i].x2, boxes[i].y2,
 | 
			
		||||
                  META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
region_to_outline (cairo_region_t *region,
 | 
			
		||||
                   GArray         *borders)
 | 
			
		||||
{
 | 
			
		||||
  MetaBox *boxes;
 | 
			
		||||
  int num_boxes;
 | 
			
		||||
  int i;
 | 
			
		||||
  int top_most, bottom_most;
 | 
			
		||||
  int current_roof;
 | 
			
		||||
  int prev_top;
 | 
			
		||||
  int band_start, prev_band_start;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Remove any overlapping lines from the set of rectangles. Note that
 | 
			
		||||
   * pixman regions are grouped as rows of rectangles, where rectangles
 | 
			
		||||
   * in one row never touch or overlap and are all of the same height.
 | 
			
		||||
   *
 | 
			
		||||
   *             -------- ---                   -------- ---
 | 
			
		||||
   *             |      | | |                   |      | | |
 | 
			
		||||
   *   ----------====---- ---         -----------  ----- ---
 | 
			
		||||
   *   |            |            =>   |            |
 | 
			
		||||
   *   ----==========---------        -----        ----------
 | 
			
		||||
   *       |                 |            |                 |
 | 
			
		||||
   *       -------------------            -------------------
 | 
			
		||||
   *
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  num_boxes  = cairo_region_num_rectangles (region);
 | 
			
		||||
  boxes = g_new (MetaBox, num_boxes);
 | 
			
		||||
  for (i = 0; i < num_boxes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      cairo_rectangle_int_t rect;
 | 
			
		||||
      cairo_region_get_rectangle (region, i, &rect);
 | 
			
		||||
      boxes[i] = (MetaBox) {
 | 
			
		||||
        .x1 = rect.x,
 | 
			
		||||
        .y1 = rect.y,
 | 
			
		||||
        .x2 = rect.x + rect.width,
 | 
			
		||||
        .y2 = rect.y + rect.height,
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  prev_top = 0;
 | 
			
		||||
  top_most = boxes[0].y1;
 | 
			
		||||
  current_roof = top_most;
 | 
			
		||||
  bottom_most = boxes[num_boxes - 1].y2;
 | 
			
		||||
  band_start = 0;
 | 
			
		||||
  prev_band_start = 0;
 | 
			
		||||
  for (i = 0; i < num_boxes; i++)
 | 
			
		||||
    {
 | 
			
		||||
      /* Detect if there is a vertical empty space, and add the lower
 | 
			
		||||
       * level of the previous band if so was the case. */
 | 
			
		||||
      if (i > 0 &&
 | 
			
		||||
          boxes[i].y1 != prev_top &&
 | 
			
		||||
          boxes[i].y1 != boxes[i - 1].y2)
 | 
			
		||||
        {
 | 
			
		||||
          current_roof = boxes[i].y1;
 | 
			
		||||
          add_band_bottom_edges (boxes,
 | 
			
		||||
                                 band_start,
 | 
			
		||||
                                 i,
 | 
			
		||||
                                 borders);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Special case adding the last band, since it won't be handled
 | 
			
		||||
       * by the band change detection below. */
 | 
			
		||||
      if (boxes[i].y1 != current_roof && i == num_boxes - 1)
 | 
			
		||||
        {
 | 
			
		||||
          if (boxes[i].y1 != prev_top)
 | 
			
		||||
            {
 | 
			
		||||
              /* The last band is a single box, so we don't
 | 
			
		||||
               * have a prev_band_start to tell us when the
 | 
			
		||||
               * previous band started. */
 | 
			
		||||
              add_non_overlapping_edges (boxes,
 | 
			
		||||
                                         band_start,
 | 
			
		||||
                                         i,
 | 
			
		||||
                                         i + 1,
 | 
			
		||||
                                         borders);
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              add_non_overlapping_edges (boxes,
 | 
			
		||||
                                         prev_band_start,
 | 
			
		||||
                                         band_start,
 | 
			
		||||
                                         i + 1,
 | 
			
		||||
                                         borders);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Detect when passing a band and combine the top border of the
 | 
			
		||||
       * just passed band with the bottom band of the previous band.
 | 
			
		||||
       */
 | 
			
		||||
      if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top)
 | 
			
		||||
        {
 | 
			
		||||
          /* Combine the two passed bands. */
 | 
			
		||||
          if (prev_top != current_roof)
 | 
			
		||||
            {
 | 
			
		||||
              add_non_overlapping_edges (boxes,
 | 
			
		||||
                                         prev_band_start,
 | 
			
		||||
                                         band_start,
 | 
			
		||||
                                         i,
 | 
			
		||||
                                         borders);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          prev_band_start = band_start;
 | 
			
		||||
          band_start = i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Add the top border if the box is part of the current roof. */
 | 
			
		||||
      if (boxes[i].y1 == current_roof)
 | 
			
		||||
        {
 | 
			
		||||
          add_border (borders,
 | 
			
		||||
                      boxes[i].x1, boxes[i].y1,
 | 
			
		||||
                      boxes[i].x2, boxes[i].y1,
 | 
			
		||||
                      META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Add the bottom border of the last band. */
 | 
			
		||||
      if (boxes[i].y2 == bottom_most)
 | 
			
		||||
        {
 | 
			
		||||
          add_border (borders,
 | 
			
		||||
                      boxes[i].x1, boxes[i].y2,
 | 
			
		||||
                      boxes[i].x2, boxes[i].y2,
 | 
			
		||||
                      META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Always add the left border. */
 | 
			
		||||
      add_border (borders,
 | 
			
		||||
                  boxes[i].x1, boxes[i].y1,
 | 
			
		||||
                  boxes[i].x1, boxes[i].y2,
 | 
			
		||||
                  META_BORDER_MOTION_DIRECTION_NEGATIVE_X);
 | 
			
		||||
 | 
			
		||||
      /* Always add the right border. */
 | 
			
		||||
      add_border (borders,
 | 
			
		||||
                  boxes[i].x2, boxes[i].y1,
 | 
			
		||||
                  boxes[i].x2, boxes[i].y2,
 | 
			
		||||
                  META_BORDER_MOTION_DIRECTION_POSITIVE_X);
 | 
			
		||||
 | 
			
		||||
      prev_top = boxes[i].y1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_free (boxes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaBorder *
 | 
			
		||||
get_closest_border (GArray    *borders,
 | 
			
		||||
                    MetaLine2 *motion,
 | 
			
		||||
                    uint32_t   directions)
 | 
			
		||||
{
 | 
			
		||||
  MetaBorder *border;
 | 
			
		||||
  MetaVector2 intersection;
 | 
			
		||||
  MetaVector2 delta;
 | 
			
		||||
  float distance_2;
 | 
			
		||||
  MetaBorder *closest_border = NULL;
 | 
			
		||||
  float closest_distance_2 = DBL_MAX;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < borders->len; i++)
 | 
			
		||||
    {
 | 
			
		||||
      border = &g_array_index (borders, MetaBorder, i);
 | 
			
		||||
 | 
			
		||||
      if (!meta_border_is_blocking_directions (border, directions))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      if (!meta_line2_intersects_with (&border->line, motion, &intersection))
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      delta = meta_vector2_subtract (intersection, motion->a);
 | 
			
		||||
      distance_2 = delta.x*delta.x + delta.y*delta.y;
 | 
			
		||||
      if (distance_2 < closest_distance_2)
 | 
			
		||||
        {
 | 
			
		||||
          closest_border = border;
 | 
			
		||||
          closest_distance_2 = distance_2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return closest_border;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
clamp_to_border (MetaBorder *border,
 | 
			
		||||
                 MetaLine2  *motion,
 | 
			
		||||
                 uint32_t   *motion_dir)
 | 
			
		||||
{
 | 
			
		||||
  /*
 | 
			
		||||
   * When clamping either rightward or downward motions, the motion needs to be
 | 
			
		||||
   * clamped so that the destination coordinate does not end up on the border
 | 
			
		||||
   * (see weston_pointer_clamp_event_to_region). Do this by clamping such
 | 
			
		||||
   * motions to the border minus the smallest possible wl_fixed_t value.
 | 
			
		||||
   *
 | 
			
		||||
   * When clamping in either leftward or upward motion, the resulting coordinate
 | 
			
		||||
   * needs to be clamped so that it is enough on the inside to avoid the
 | 
			
		||||
   * inaccuracies of clutter's stage to actor transformation algorithm (the one
 | 
			
		||||
   * used in clutter_actor_transform_stage_point) to make it end up outside the
 | 
			
		||||
   * next motion. It also needs to be clamped so that to the wl_fixed_t
 | 
			
		||||
   * coordinate may still be right on the border (i.e. at .0). Testing shows
 | 
			
		||||
   * that the smallest wl_fixed_t value divided by 10 is small enough to make
 | 
			
		||||
   * the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of
 | 
			
		||||
   * clutters transform algorithm.
 | 
			
		||||
   */
 | 
			
		||||
  if (meta_border_is_horizontal (border))
 | 
			
		||||
    {
 | 
			
		||||
      if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y)
 | 
			
		||||
        motion->b.y = border->line.a.y - wl_fixed_to_double (1);
 | 
			
		||||
      else
 | 
			
		||||
        motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10;
 | 
			
		||||
      *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
 | 
			
		||||
                       META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X)
 | 
			
		||||
        motion->b.x = border->line.a.x - wl_fixed_to_double (1);
 | 
			
		||||
      else
 | 
			
		||||
        motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10;
 | 
			
		||||
      *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X |
 | 
			
		||||
                       META_BORDER_MOTION_DIRECTION_NEGATIVE_X);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t
 | 
			
		||||
get_motion_directions (MetaLine2 *motion)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t directions = 0;
 | 
			
		||||
 | 
			
		||||
  if (motion->a.x < motion->b.x)
 | 
			
		||||
    directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X;
 | 
			
		||||
  else if (motion->a.x > motion->b.x)
 | 
			
		||||
    directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X;
 | 
			
		||||
  if (motion->a.y < motion->b.y)
 | 
			
		||||
    directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y;
 | 
			
		||||
  else if (motion->a.y > motion->b.y)
 | 
			
		||||
    directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y;
 | 
			
		||||
 | 
			
		||||
  return directions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_confinement_wayland_constrain (MetaPointerConstraint *constraint,
 | 
			
		||||
                                            ClutterInputDevice    *device,
 | 
			
		||||
                                            guint32                time,
 | 
			
		||||
                                            float                  prev_x,
 | 
			
		||||
                                            float                  prev_y,
 | 
			
		||||
                                            float                  *x,
 | 
			
		||||
                                            float                  *y)
 | 
			
		||||
{
 | 
			
		||||
  MetaPointerConfinementWayland *self =
 | 
			
		||||
    META_POINTER_CONFINEMENT_WAYLAND (constraint);
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
  float sx, sy;
 | 
			
		||||
  float prev_sx, prev_sy;
 | 
			
		||||
  GArray *borders;
 | 
			
		||||
  MetaLine2 motion;
 | 
			
		||||
  MetaBorder *closest_border;
 | 
			
		||||
  uint32_t directions;
 | 
			
		||||
 | 
			
		||||
  surface = meta_wayland_pointer_constraint_get_surface (self->constraint);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_surface_get_relative_coordinates (surface, *x, *y, &sx, &sy);
 | 
			
		||||
  meta_wayland_surface_get_relative_coordinates (surface, prev_x, prev_y,
 | 
			
		||||
                                                 &prev_sx, &prev_sy);
 | 
			
		||||
 | 
			
		||||
  /* For motions in a positive direction on any axis, append the smallest
 | 
			
		||||
   * possible value representable in a Wayland absolute coordinate.  This is
 | 
			
		||||
   * in order to avoid not clamping motion that as a floating point number
 | 
			
		||||
   * won't be clamped, but will be rounded up to be outside of the range
 | 
			
		||||
   * of wl_fixed_t. */
 | 
			
		||||
  if (sx > prev_sx)
 | 
			
		||||
    sx += (float)wl_fixed_to_double(1);
 | 
			
		||||
  if (sy > prev_sy)
 | 
			
		||||
    sy += (float)wl_fixed_to_double(1);
 | 
			
		||||
 | 
			
		||||
  borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder));
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generate borders given the confine region we are to use. The borders
 | 
			
		||||
   * are defined to be the outer region of the allowed area. This means
 | 
			
		||||
   * top/left borders are "within" the allowed area, while bottom/right
 | 
			
		||||
   * borders are outside. This needs to be considered when clamping
 | 
			
		||||
   * confined motion vectors.
 | 
			
		||||
   */
 | 
			
		||||
  region =
 | 
			
		||||
    meta_wayland_pointer_constraint_calculate_effective_region (self->constraint);
 | 
			
		||||
  region_to_outline (region, borders);
 | 
			
		||||
  cairo_region_destroy (region);
 | 
			
		||||
 | 
			
		||||
  motion = (MetaLine2) {
 | 
			
		||||
    .a = (MetaVector2) {
 | 
			
		||||
      .x = prev_sx,
 | 
			
		||||
      .y = prev_sy,
 | 
			
		||||
    },
 | 
			
		||||
    .b = (MetaVector2) {
 | 
			
		||||
      .x = sx,
 | 
			
		||||
      .y = sy,
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  directions = get_motion_directions (&motion);
 | 
			
		||||
 | 
			
		||||
  while (directions)
 | 
			
		||||
    {
 | 
			
		||||
      closest_border = get_closest_border (borders,
 | 
			
		||||
                                           &motion,
 | 
			
		||||
                                           directions);
 | 
			
		||||
      if (closest_border)
 | 
			
		||||
        clamp_to_border (closest_border, &motion, &directions);
 | 
			
		||||
      else
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_surface_get_absolute_coordinates (surface,
 | 
			
		||||
                                                 motion.b.x, motion.b.y,
 | 
			
		||||
                                                 x, y);
 | 
			
		||||
 | 
			
		||||
  g_array_free (borders, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float
 | 
			
		||||
point_to_border_distance_2 (MetaBorder *border,
 | 
			
		||||
                            float       x,
 | 
			
		||||
                            float       y)
 | 
			
		||||
{
 | 
			
		||||
  float orig_x, orig_y;
 | 
			
		||||
  float dx, dy;
 | 
			
		||||
 | 
			
		||||
  if (meta_border_is_horizontal (border))
 | 
			
		||||
    {
 | 
			
		||||
      if (x < border->line.a.x)
 | 
			
		||||
        orig_x = border->line.a.x;
 | 
			
		||||
      else if (x > border->line.b.x)
 | 
			
		||||
        orig_x = border->line.b.x;
 | 
			
		||||
      else
 | 
			
		||||
        orig_x = x;
 | 
			
		||||
      orig_y = border->line.a.y;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (y < border->line.a.y)
 | 
			
		||||
        orig_y = border->line.a.y;
 | 
			
		||||
      else if (y > border->line.b.y)
 | 
			
		||||
        orig_y = border->line.b.y;
 | 
			
		||||
      else
 | 
			
		||||
        orig_y = y;
 | 
			
		||||
      orig_x = border->line.a.x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  dx = fabsf (orig_x - x);
 | 
			
		||||
  dy = fabsf (orig_y - y);
 | 
			
		||||
  return dx*dx + dy*dy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
warp_to_behind_border (MetaBorder *border,
 | 
			
		||||
                       float      *sx,
 | 
			
		||||
                       float      *sy)
 | 
			
		||||
{
 | 
			
		||||
  switch (border->blocking_directions)
 | 
			
		||||
    {
 | 
			
		||||
    case META_BORDER_MOTION_DIRECTION_POSITIVE_X:
 | 
			
		||||
    case META_BORDER_MOTION_DIRECTION_NEGATIVE_X:
 | 
			
		||||
      if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X)
 | 
			
		||||
        *sx = border->line.a.x - wl_fixed_to_double (1);
 | 
			
		||||
      else
 | 
			
		||||
        *sx = border->line.a.x + wl_fixed_to_double (1);
 | 
			
		||||
      if (*sy < border->line.a.y)
 | 
			
		||||
        *sy = border->line.a.y + wl_fixed_to_double (1);
 | 
			
		||||
      else if (*sy > border->line.b.y)
 | 
			
		||||
        *sy = border->line.b.y - wl_fixed_to_double (1);
 | 
			
		||||
      break;
 | 
			
		||||
    case META_BORDER_MOTION_DIRECTION_POSITIVE_Y:
 | 
			
		||||
    case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y:
 | 
			
		||||
      if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y)
 | 
			
		||||
        *sy = border->line.a.y - wl_fixed_to_double (1);
 | 
			
		||||
      else
 | 
			
		||||
        *sy = border->line.a.y + wl_fixed_to_double (1);
 | 
			
		||||
      if (*sx < border->line.a.x)
 | 
			
		||||
        *sx = border->line.a.x + wl_fixed_to_double (1);
 | 
			
		||||
      else if (*sx > (border->line.b.x))
 | 
			
		||||
        *sx = border->line.b.x - wl_fixed_to_double (1);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_confinement_wayland_maybe_warp (MetaPointerConfinementWayland *self)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat;
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
  ClutterPoint point;
 | 
			
		||||
  float sx;
 | 
			
		||||
  float sy;
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
 | 
			
		||||
  seat = meta_wayland_pointer_constraint_get_seat (self->constraint);
 | 
			
		||||
  surface = meta_wayland_pointer_constraint_get_surface (self->constraint);
 | 
			
		||||
 | 
			
		||||
  clutter_input_device_get_coords (seat->pointer.device, NULL, &point);
 | 
			
		||||
  meta_wayland_surface_get_relative_coordinates (surface,
 | 
			
		||||
                                                 point.x, point.y,
 | 
			
		||||
                                                 &sx, &sy);
 | 
			
		||||
 | 
			
		||||
  region =
 | 
			
		||||
    meta_wayland_pointer_constraint_calculate_effective_region (self->constraint);
 | 
			
		||||
 | 
			
		||||
  if (!cairo_region_contains_point (region, (int)sx, (int)sy))
 | 
			
		||||
    {
 | 
			
		||||
      GArray *borders;
 | 
			
		||||
      float closest_distance_2 = FLT_MAX;
 | 
			
		||||
      MetaBorder *closest_border = NULL;
 | 
			
		||||
      unsigned int i;
 | 
			
		||||
      float x;
 | 
			
		||||
      float y;
 | 
			
		||||
 | 
			
		||||
      borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder));
 | 
			
		||||
 | 
			
		||||
      region_to_outline (region, borders);
 | 
			
		||||
 | 
			
		||||
      for (i = 0; i < borders->len; i++)
 | 
			
		||||
        {
 | 
			
		||||
          MetaBorder *border = &g_array_index (borders, MetaBorder, i);
 | 
			
		||||
          float distance_2;
 | 
			
		||||
 | 
			
		||||
          distance_2 = point_to_border_distance_2 (border, sx, sy);
 | 
			
		||||
          if (distance_2 < closest_distance_2)
 | 
			
		||||
            {
 | 
			
		||||
              closest_border = border;
 | 
			
		||||
              closest_distance_2 = distance_2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      warp_to_behind_border (closest_border, &sx, &sy);
 | 
			
		||||
 | 
			
		||||
      meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y);
 | 
			
		||||
      meta_backend_warp_pointer (meta_get_backend (), (int)x, (int)y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  cairo_region_destroy (region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
surface_actor_painting (MetaSurfaceActorWayland       *surface_actor,
 | 
			
		||||
                        MetaPointerConfinementWayland *self)
 | 
			
		||||
{
 | 
			
		||||
  meta_pointer_confinement_wayland_maybe_warp (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaPointerConstraint *
 | 
			
		||||
meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  GObject *object;
 | 
			
		||||
  MetaPointerConfinementWayland *confinement;
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
 | 
			
		||||
  object = g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, NULL);
 | 
			
		||||
  confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
 | 
			
		||||
 | 
			
		||||
  confinement->constraint = constraint;
 | 
			
		||||
 | 
			
		||||
  surface = meta_wayland_pointer_constraint_get_surface (constraint);
 | 
			
		||||
  g_signal_connect_object (surface->surface_actor,
 | 
			
		||||
                           "painting",
 | 
			
		||||
                           G_CALLBACK (surface_actor_painting),
 | 
			
		||||
                           confinement,
 | 
			
		||||
                           0);
 | 
			
		||||
 | 
			
		||||
  return META_POINTER_CONSTRAINT (confinement);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinement_wayland)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaPointerConstraintClass *pointer_constraint_class =
 | 
			
		||||
    META_POINTER_CONSTRAINT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  pointer_constraint_class->constrain = meta_pointer_confinement_wayland_constrain;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/wayland/meta-pointer-confinement-wayland.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/wayland/meta-pointer-confinement-wayland.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_POINTER_CONFINEMENT_WAYLAND_H
 | 
			
		||||
#define META_POINTER_CONFINEMENT_WAYLAND_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
#include "wayland/meta-wayland-pointer-constraints.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaPointerConfinementWayland,
 | 
			
		||||
                      meta_pointer_confinement_wayland,
 | 
			
		||||
                      META, POINTER_CONFINEMENT_WAYLAND,
 | 
			
		||||
                      MetaPointerConstraint);
 | 
			
		||||
 | 
			
		||||
MetaPointerConstraint *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* META_CONFINEMENT_WAYLAND_H */
 | 
			
		||||
							
								
								
									
										72
									
								
								src/wayland/meta-pointer-lock-wayland.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/wayland/meta-pointer-lock-wayland.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "wayland/meta-pointer-lock-wayland.h"
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
 | 
			
		||||
struct _MetaPointerLockWayland
 | 
			
		||||
{
 | 
			
		||||
  MetaPointerConstraint parent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
 | 
			
		||||
               META_TYPE_POINTER_CONSTRAINT);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint,
 | 
			
		||||
                                     ClutterInputDevice    *device,
 | 
			
		||||
                                     guint32                time,
 | 
			
		||||
                                     float                  prev_x,
 | 
			
		||||
                                     float                  prev_y,
 | 
			
		||||
                                     float                 *x,
 | 
			
		||||
                                     float                 *y)
 | 
			
		||||
{
 | 
			
		||||
  *x = prev_x;
 | 
			
		||||
  *y = prev_y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaPointerConstraint *
 | 
			
		||||
meta_pointer_lock_wayland_new (void)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_lock_wayland_init (MetaPointerLockWayland *lock_wayland)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  MetaPointerConstraintClass *pointer_constraint_class =
 | 
			
		||||
    META_POINTER_CONSTRAINT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  pointer_constraint_class->constrain = meta_pointer_lock_wayland_constrain;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/wayland/meta-pointer-lock-wayland.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/wayland/meta-pointer-lock-wayland.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_POINTER_LOCK_WAYLAND_H
 | 
			
		||||
#define META_POINTER_LOCK_WAYLAND_H
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
 | 
			
		||||
                      META, POINTER_LOCK_WAYLAND, MetaPointerConstraint);
 | 
			
		||||
 | 
			
		||||
MetaPointerConstraint *meta_pointer_lock_wayland_new (void);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* META_LOCK_WAYLAND_H */
 | 
			
		||||
@@ -54,10 +54,31 @@ meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
 | 
			
		||||
  if (buffer->ref_count == 0)
 | 
			
		||||
    {
 | 
			
		||||
      g_clear_pointer (&buffer->texture, cogl_object_unref);
 | 
			
		||||
      wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
 | 
			
		||||
 | 
			
		||||
      if (buffer->accessible)
 | 
			
		||||
        meta_wayland_buffer_release_control (buffer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_buffer_take_control (MetaWaylandBuffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
  if (buffer->accessible)
 | 
			
		||||
    meta_fatal ("buffer control taken twice");
 | 
			
		||||
 | 
			
		||||
  buffer->accessible = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_buffer_release_control (MetaWaylandBuffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
  if (!buffer->accessible)
 | 
			
		||||
    meta_fatal ("buffer released when not in control");
 | 
			
		||||
 | 
			
		||||
  wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
 | 
			
		||||
  buffer->accessible = FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandBuffer *
 | 
			
		||||
meta_wayland_buffer_from_resource (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
@@ -93,6 +114,9 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
 | 
			
		||||
  CoglTexture *texture;
 | 
			
		||||
  struct wl_shm_buffer *shm_buffer;
 | 
			
		||||
 | 
			
		||||
  if (!buffer->accessible)
 | 
			
		||||
    meta_warning ("attempted to process damage on uncommitted buffer");
 | 
			
		||||
 | 
			
		||||
  if (buffer->texture)
 | 
			
		||||
    goto out;
 | 
			
		||||
 | 
			
		||||
@@ -116,6 +140,9 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
 | 
			
		||||
 | 
			
		||||
  buffer->texture = texture;
 | 
			
		||||
 | 
			
		||||
  if (shm_buffer)
 | 
			
		||||
    buffer->copied_data = TRUE;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
  return buffer->texture;
 | 
			
		||||
}
 | 
			
		||||
@@ -126,6 +153,9 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
 | 
			
		||||
{
 | 
			
		||||
  struct wl_shm_buffer *shm_buffer;
 | 
			
		||||
 | 
			
		||||
  if (!buffer->accessible)
 | 
			
		||||
    meta_warning ("attempted to process damage on uncommitted buffer");
 | 
			
		||||
 | 
			
		||||
  shm_buffer = wl_shm_buffer_get (buffer->resource);
 | 
			
		||||
 | 
			
		||||
  if (shm_buffer)
 | 
			
		||||
 
 | 
			
		||||
@@ -39,11 +39,16 @@ struct _MetaWaylandBuffer
 | 
			
		||||
 | 
			
		||||
  CoglTexture *texture;
 | 
			
		||||
  uint32_t ref_count;
 | 
			
		||||
 | 
			
		||||
  uint32_t accessible : 1;
 | 
			
		||||
  uint32_t copied_data : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MetaWaylandBuffer *     meta_wayland_buffer_from_resource       (struct wl_resource    *resource);
 | 
			
		||||
void                    meta_wayland_buffer_ref                 (MetaWaylandBuffer     *buffer);
 | 
			
		||||
void                    meta_wayland_buffer_unref               (MetaWaylandBuffer     *buffer);
 | 
			
		||||
void                    meta_wayland_buffer_take_control        (MetaWaylandBuffer     *buffer);
 | 
			
		||||
void                    meta_wayland_buffer_release_control     (MetaWaylandBuffer     *buffer);
 | 
			
		||||
CoglTexture *           meta_wayland_buffer_ensure_texture      (MetaWaylandBuffer     *buffer);
 | 
			
		||||
void                    meta_wayland_buffer_process_damage      (MetaWaylandBuffer     *buffer,
 | 
			
		||||
                                                                 cairo_region_t        *region);
 | 
			
		||||
 
 | 
			
		||||
@@ -37,17 +37,30 @@
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-dnd-actor-private.h"
 | 
			
		||||
 | 
			
		||||
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
 | 
			
		||||
                     WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
 | 
			
		||||
                     WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandDataOffer
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  MetaWaylandDataSource *source;
 | 
			
		||||
  struct wl_listener source_destroy_listener;
 | 
			
		||||
  uint32_t dnd_actions;
 | 
			
		||||
  enum wl_data_device_manager_dnd_action preferred_dnd_action;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandDataSourcePrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer;
 | 
			
		||||
  struct wl_array mime_types;
 | 
			
		||||
  gboolean has_target;
 | 
			
		||||
  uint32_t dnd_actions;
 | 
			
		||||
  enum wl_data_device_manager_dnd_action user_dnd_action;
 | 
			
		||||
  enum wl_data_device_manager_dnd_action current_dnd_action;
 | 
			
		||||
  MetaWaylandSeat *seat;
 | 
			
		||||
  guint actions_set : 1;
 | 
			
		||||
  guint in_ask : 1;
 | 
			
		||||
} MetaWaylandDataSourcePrivate;
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandDataSourceWayland
 | 
			
		||||
@@ -74,6 +87,75 @@ unbind_resource (struct wl_resource *resource)
 | 
			
		||||
  wl_list_remove (wl_resource_get_link (resource));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_wayland_source_get_in_ask (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  return priv->in_ask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_source_update_in_ask (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  priv->in_ask =
 | 
			
		||||
    priv->current_dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum wl_data_device_manager_dnd_action
 | 
			
		||||
data_offer_choose_action (MetaWaylandDataOffer *offer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSource *source = offer->source;
 | 
			
		||||
  uint32_t actions, user_action, available_actions;
 | 
			
		||||
 | 
			
		||||
  actions = meta_wayland_data_source_get_actions (source);
 | 
			
		||||
  user_action = meta_wayland_data_source_get_user_action (source);
 | 
			
		||||
 | 
			
		||||
  available_actions = actions & offer->dnd_actions;
 | 
			
		||||
 | 
			
		||||
  if (!available_actions)
 | 
			
		||||
    return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 | 
			
		||||
 | 
			
		||||
  /* If the user is forcing an action, go for it */
 | 
			
		||||
  if ((user_action & available_actions) != 0)
 | 
			
		||||
    return user_action;
 | 
			
		||||
 | 
			
		||||
  /* If the dest side has a preferred DnD action, use it */
 | 
			
		||||
  if ((offer->preferred_dnd_action & available_actions) != 0)
 | 
			
		||||
    return offer->preferred_dnd_action;
 | 
			
		||||
 | 
			
		||||
  /* Use the first found action, in bit order */
 | 
			
		||||
  return 1 << (ffs (available_actions) - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_update_action (MetaWaylandDataOffer *offer)
 | 
			
		||||
{
 | 
			
		||||
  enum wl_data_device_manager_dnd_action current_action, action;
 | 
			
		||||
  MetaWaylandDataSource *source;
 | 
			
		||||
 | 
			
		||||
  if (!offer->source)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  source = offer->source;
 | 
			
		||||
  current_action = meta_wayland_data_source_get_current_action (source);
 | 
			
		||||
  action = data_offer_choose_action (offer);
 | 
			
		||||
 | 
			
		||||
  if (current_action == action)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_data_source_set_current_action (source, action);
 | 
			
		||||
 | 
			
		||||
  if (!meta_wayland_source_get_in_ask (source) &&
 | 
			
		||||
      wl_resource_get_version (offer->resource) >=
 | 
			
		||||
      WL_DATA_OFFER_ACTION_SINCE_VERSION)
 | 
			
		||||
    wl_data_offer_send_action (offer->resource, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_data_source_target (MetaWaylandDataSource *source,
 | 
			
		||||
                                 const char *mime_type)
 | 
			
		||||
@@ -98,6 +180,25 @@ meta_wayland_data_source_has_target (MetaWaylandDataSource *source)
 | 
			
		||||
  return priv->has_target;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_data_source_set_seat (MetaWaylandDataSource *source,
 | 
			
		||||
                                   MetaWaylandSeat       *seat)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  priv->seat = seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandSeat *
 | 
			
		||||
meta_wayland_data_source_get_seat (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  return priv->seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_source_set_has_target (MetaWaylandDataSource *source,
 | 
			
		||||
                                         gboolean has_target)
 | 
			
		||||
@@ -112,7 +213,7 @@ struct wl_array *
 | 
			
		||||
meta_wayland_data_source_get_mime_types (const MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
    meta_wayland_data_source_get_instance_private ((MetaWaylandDataSource *)source);
 | 
			
		||||
 | 
			
		||||
  return &priv->mime_types;
 | 
			
		||||
}
 | 
			
		||||
@@ -123,6 +224,100 @@ meta_wayland_data_source_cancel (MetaWaylandDataSource *source)
 | 
			
		||||
  META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->cancel (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
meta_wayland_data_source_get_actions (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  return priv->dnd_actions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wl_data_device_manager_dnd_action
 | 
			
		||||
meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  if (!priv->seat)
 | 
			
		||||
    return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 | 
			
		||||
 | 
			
		||||
  return priv->user_dnd_action;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wl_data_device_manager_dnd_action
 | 
			
		||||
meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  return priv->current_dnd_action;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_data_source_set_current_offer (MetaWaylandDataSource *source,
 | 
			
		||||
                                            MetaWaylandDataOffer  *offer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  priv->offer = offer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandDataOffer *
 | 
			
		||||
meta_wayland_data_source_get_current_offer (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  return priv->offer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_source_set_current_action (MetaWaylandDataSource                  *source,
 | 
			
		||||
                                             enum wl_data_device_manager_dnd_action  action)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  if (priv->current_dnd_action == action)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  priv->current_dnd_action = action;
 | 
			
		||||
 | 
			
		||||
  if (!meta_wayland_source_get_in_ask (source))
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->action (source, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
 | 
			
		||||
                                      uint32_t               dnd_actions)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  priv->dnd_actions = dnd_actions;
 | 
			
		||||
  priv->actions_set = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_data_source_set_user_action (MetaWaylandDataSource                  *source,
 | 
			
		||||
                                          enum wl_data_device_manager_dnd_action  action)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
  MetaWaylandDataOffer *offer;
 | 
			
		||||
 | 
			
		||||
  if (priv->user_dnd_action == action)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  priv->user_dnd_action = action;
 | 
			
		||||
  offer = meta_wayland_data_source_get_current_offer (source);
 | 
			
		||||
 | 
			
		||||
  if (offer)
 | 
			
		||||
    data_offer_update_action (offer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_accept (struct wl_client *client,
 | 
			
		||||
                   struct wl_resource *resource,
 | 
			
		||||
@@ -161,21 +356,117 @@ data_offer_destroy (struct wl_client *client, struct wl_resource *resource)
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_finish (struct wl_client   *client,
 | 
			
		||||
		   struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
 | 
			
		||||
  enum wl_data_device_manager_dnd_action current_action;
 | 
			
		||||
 | 
			
		||||
  if (!offer->source ||
 | 
			
		||||
      offer != meta_wayland_data_source_get_current_offer (offer->source))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (meta_wayland_data_source_get_seat (offer->source) ||
 | 
			
		||||
      !meta_wayland_data_source_has_target (offer->source))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (offer->resource,
 | 
			
		||||
                              WL_DATA_OFFER_ERROR_INVALID_FINISH,
 | 
			
		||||
                              "premature finish request");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  current_action = meta_wayland_data_source_get_current_action (offer->source);
 | 
			
		||||
 | 
			
		||||
  if (current_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE ||
 | 
			
		||||
      current_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (offer->resource,
 | 
			
		||||
                              WL_DATA_OFFER_ERROR_INVALID_OFFER,
 | 
			
		||||
                              "offer finished with an invalid action");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_data_source_notify_finish (offer->source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_offer_set_actions (struct wl_client   *client,
 | 
			
		||||
                        struct wl_resource *resource,
 | 
			
		||||
                        uint32_t            dnd_actions,
 | 
			
		||||
                        uint32_t            preferred_action)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  if (dnd_actions & ~(ALL_ACTIONS))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (offer->resource,
 | 
			
		||||
                              WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
 | 
			
		||||
                              "invalid actions mask %x", dnd_actions);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (preferred_action &&
 | 
			
		||||
      (!(preferred_action & dnd_actions) ||
 | 
			
		||||
       __builtin_popcount (preferred_action) > 1))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (offer->resource,
 | 
			
		||||
                              WL_DATA_OFFER_ERROR_INVALID_ACTION,
 | 
			
		||||
                              "invalid action %x", preferred_action);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  offer->dnd_actions = dnd_actions;
 | 
			
		||||
  offer->preferred_dnd_action = preferred_action;
 | 
			
		||||
 | 
			
		||||
  data_offer_update_action (offer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_data_offer_interface data_offer_interface = {
 | 
			
		||||
  data_offer_accept,
 | 
			
		||||
  data_offer_receive,
 | 
			
		||||
  data_offer_destroy,
 | 
			
		||||
  data_offer_finish,
 | 
			
		||||
  data_offer_set_actions,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drop_performed (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drag_finished (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_data_offer (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  if (offer->source)
 | 
			
		||||
    g_object_remove_weak_pointer (G_OBJECT (offer->source),
 | 
			
		||||
                                  (gpointer *)&offer->source);
 | 
			
		||||
    {
 | 
			
		||||
      if (offer == meta_wayland_data_source_get_current_offer (offer->source))
 | 
			
		||||
        {
 | 
			
		||||
          if (wl_resource_get_version (offer->resource) <
 | 
			
		||||
              WL_DATA_OFFER_ACTION_SINCE_VERSION)
 | 
			
		||||
            meta_wayland_data_source_notify_finish (offer->source);
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              meta_wayland_data_source_cancel (offer->source);
 | 
			
		||||
              meta_wayland_data_source_set_current_offer (offer->source, NULL);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      g_object_remove_weak_pointer (G_OBJECT (offer->source),
 | 
			
		||||
                                    (gpointer *)&offer->source);
 | 
			
		||||
      offer->source = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_display_sync_wayland_input_focus (meta_get_display ());
 | 
			
		||||
  g_slice_free (MetaWaylandDataOffer, offer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -203,6 +494,9 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
 | 
			
		||||
  wl_array_for_each (p, &priv->mime_types)
 | 
			
		||||
    wl_data_offer_send_offer (offer->resource, *p);
 | 
			
		||||
 | 
			
		||||
  data_offer_update_action (offer);
 | 
			
		||||
  meta_wayland_data_source_set_current_offer (source, offer);
 | 
			
		||||
 | 
			
		||||
  return offer->resource;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -222,14 +516,56 @@ data_source_destroy (struct wl_client *client, struct wl_resource *resource)
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_source_set_actions (struct wl_client   *client,
 | 
			
		||||
                         struct wl_resource *resource,
 | 
			
		||||
                         uint32_t            dnd_actions)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
  MetaWaylandDataSourceWayland *source_wayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_WAYLAND (source);
 | 
			
		||||
 | 
			
		||||
  if (priv->actions_set)
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (source_wayland->resource,
 | 
			
		||||
                              WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
 | 
			
		||||
                              "cannot set actions more than once");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (dnd_actions & ~(ALL_ACTIONS))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (source_wayland->resource,
 | 
			
		||||
                              WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
 | 
			
		||||
                              "invalid actions mask %x", dnd_actions);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (meta_wayland_data_source_get_seat (source))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (source_wayland->resource,
 | 
			
		||||
                              WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
 | 
			
		||||
                              "invalid action change after "
 | 
			
		||||
                              "wl_data_device.start_drag");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_data_source_set_actions (source, dnd_actions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wl_data_source_interface data_source_interface = {
 | 
			
		||||
  data_source_offer,
 | 
			
		||||
  data_source_destroy
 | 
			
		||||
  data_source_destroy,
 | 
			
		||||
  data_source_set_actions
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandDragGrab {
 | 
			
		||||
  MetaWaylandPointerGrab  generic;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandKeyboardGrab keyboard_grab;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandSeat        *seat;
 | 
			
		||||
  struct wl_client       *drag_client;
 | 
			
		||||
 | 
			
		||||
@@ -248,6 +584,7 @@ struct _MetaWaylandDragGrab {
 | 
			
		||||
  struct wl_listener      drag_origin_listener;
 | 
			
		||||
 | 
			
		||||
  int                     drag_start_x, drag_start_y;
 | 
			
		||||
  ClutterModifierType     buttons;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -256,6 +593,24 @@ destroy_drag_focus (struct wl_listener *listener, void *data)
 | 
			
		||||
  MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener);
 | 
			
		||||
 | 
			
		||||
  grab->drag_focus_data_device = NULL;
 | 
			
		||||
  grab->drag_focus = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_drag_grab_set_source (MetaWaylandDragGrab   *drag_grab,
 | 
			
		||||
                                   MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  if (drag_grab->drag_data_source)
 | 
			
		||||
    g_object_weak_unref (G_OBJECT (drag_grab->drag_data_source),
 | 
			
		||||
                         drag_grab_data_source_destroyed,
 | 
			
		||||
                         drag_grab);
 | 
			
		||||
 | 
			
		||||
  drag_grab->drag_data_source = source;
 | 
			
		||||
 | 
			
		||||
  if (source)
 | 
			
		||||
    g_object_weak_ref (G_OBJECT (source),
 | 
			
		||||
                       drag_grab_data_source_destroyed,
 | 
			
		||||
                       drag_grab);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -275,6 +630,9 @@ meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
 | 
			
		||||
      drag_grab->drag_focus = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (drag_grab->drag_data_source)
 | 
			
		||||
    meta_wayland_data_source_set_current_offer (drag_grab->drag_data_source, NULL);
 | 
			
		||||
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
@@ -312,6 +670,22 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
 | 
			
		||||
  meta_wayland_drag_grab_set_focus (drag_grab, surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
data_source_update_user_dnd_action (MetaWaylandDataSource *source,
 | 
			
		||||
                                    ClutterModifierType    modifiers)
 | 
			
		||||
{
 | 
			
		||||
  enum wl_data_device_manager_dnd_action user_dnd_action = 0;
 | 
			
		||||
 | 
			
		||||
  if (modifiers & CLUTTER_SHIFT_MASK)
 | 
			
		||||
    user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
 | 
			
		||||
  else if (modifiers & CLUTTER_CONTROL_MASK)
 | 
			
		||||
    user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
 | 
			
		||||
  else if (modifiers & (CLUTTER_MOD1_MASK | CLUTTER_BUTTON2_MASK))
 | 
			
		||||
    user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_data_source_set_user_action (source, user_dnd_action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drag_grab_motion (MetaWaylandPointerGrab *grab,
 | 
			
		||||
		  const ClutterEvent     *event)
 | 
			
		||||
@@ -343,10 +717,7 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
 | 
			
		||||
      wl_list_remove (&drag_grab->drag_icon_listener.link);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (drag_grab->drag_data_source)
 | 
			
		||||
    g_object_weak_unref (G_OBJECT (drag_grab->drag_data_source),
 | 
			
		||||
                         drag_grab_data_source_destroyed,
 | 
			
		||||
                         drag_grab);
 | 
			
		||||
  meta_wayland_drag_grab_set_source (drag_grab, NULL);
 | 
			
		||||
 | 
			
		||||
  if (drag_grab->feedback_actor)
 | 
			
		||||
    {
 | 
			
		||||
@@ -356,7 +727,15 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
 | 
			
		||||
 | 
			
		||||
  drag_grab->seat->data_device.current_grab = NULL;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
 | 
			
		||||
  /* There might be other grabs created in result to DnD actions like popups
 | 
			
		||||
   * on "ask" actions, we must not reset those, only our own.
 | 
			
		||||
   */
 | 
			
		||||
  if (drag_grab->generic.pointer->grab == (MetaWaylandPointerGrab *) drag_grab)
 | 
			
		||||
    {
 | 
			
		||||
      meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
 | 
			
		||||
      meta_wayland_keyboard_end_grab (drag_grab->keyboard_grab.keyboard);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_slice_free (MetaWaylandDragGrab, drag_grab);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -371,17 +750,33 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
 | 
			
		||||
  if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
 | 
			
		||||
      event_type == CLUTTER_BUTTON_RELEASE)
 | 
			
		||||
    {
 | 
			
		||||
      gboolean success = FALSE;
 | 
			
		||||
      MetaWaylandDataSource *source = drag_grab->drag_data_source;
 | 
			
		||||
      gboolean success;
 | 
			
		||||
 | 
			
		||||
      if (meta_wayland_data_source_has_target (drag_grab->drag_data_source))
 | 
			
		||||
      if (drag_grab->drag_focus && source &&
 | 
			
		||||
          meta_wayland_data_source_has_target (source) &&
 | 
			
		||||
          meta_wayland_data_source_get_current_action (source))
 | 
			
		||||
        {
 | 
			
		||||
          /* Detach the data source from the grab, it's meant to live longer */
 | 
			
		||||
          meta_wayland_drag_grab_set_source (drag_grab, NULL);
 | 
			
		||||
          meta_wayland_data_source_set_seat (source, NULL);
 | 
			
		||||
 | 
			
		||||
          meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus);
 | 
			
		||||
          meta_wayland_data_source_notify_drop_performed (source);
 | 
			
		||||
 | 
			
		||||
          meta_wayland_source_update_in_ask (source);
 | 
			
		||||
          success = TRUE;
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          meta_wayland_data_source_cancel (source);
 | 
			
		||||
          meta_wayland_data_source_set_current_offer (source, NULL);
 | 
			
		||||
          meta_wayland_data_device_set_dnd_source (&seat->data_device, NULL);
 | 
			
		||||
          success= FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      /* Finish drag and let actor self-destruct */
 | 
			
		||||
      meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor),
 | 
			
		||||
                                  success);
 | 
			
		||||
      meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor), success);
 | 
			
		||||
      drag_grab->feedback_actor = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -396,6 +791,40 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
 | 
			
		||||
  drag_grab_button,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
keyboard_drag_grab_key (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                        const ClutterEvent      *event)
 | 
			
		||||
{
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
keyboard_drag_grab_modifiers (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                              ClutterModifierType      modifiers)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDragGrab *drag_grab;
 | 
			
		||||
 | 
			
		||||
  drag_grab = wl_container_of (grab, drag_grab, keyboard_grab);
 | 
			
		||||
 | 
			
		||||
  /* The modifiers here just contain keyboard modifiers, mix it with the
 | 
			
		||||
   * mouse button modifiers we got when starting the drag operation.
 | 
			
		||||
   */
 | 
			
		||||
  modifiers |= drag_grab->buttons;
 | 
			
		||||
 | 
			
		||||
  if (drag_grab->drag_data_source)
 | 
			
		||||
    {
 | 
			
		||||
      data_source_update_user_dnd_action (drag_grab->drag_data_source, modifiers);
 | 
			
		||||
 | 
			
		||||
      if (drag_grab->drag_focus)
 | 
			
		||||
        meta_wayland_surface_drag_dest_update (drag_grab->drag_focus);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandKeyboardGrabInterface keyboard_drag_grab_interface = {
 | 
			
		||||
  keyboard_drag_grab_key,
 | 
			
		||||
  keyboard_drag_grab_modifiers
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
destroy_data_device_origin (struct wl_listener *listener, void *data)
 | 
			
		||||
{
 | 
			
		||||
@@ -440,12 +869,16 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice                 *data
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
 | 
			
		||||
  MetaWaylandDragGrab *drag_grab;
 | 
			
		||||
  ClutterPoint pos, stage_pos;
 | 
			
		||||
  ClutterModifierType modifiers;
 | 
			
		||||
 | 
			
		||||
  data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
 | 
			
		||||
 | 
			
		||||
  drag_grab->generic.interface = funcs;
 | 
			
		||||
  drag_grab->generic.pointer = &seat->pointer;
 | 
			
		||||
 | 
			
		||||
  drag_grab->keyboard_grab.interface = &keyboard_drag_grab_interface;
 | 
			
		||||
  drag_grab->keyboard_grab.keyboard = &seat->keyboard;
 | 
			
		||||
 | 
			
		||||
  drag_grab->drag_client = client;
 | 
			
		||||
  drag_grab->seat = seat;
 | 
			
		||||
 | 
			
		||||
@@ -460,13 +893,15 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice                 *data
 | 
			
		||||
  drag_grab->drag_start_x = stage_pos.x;
 | 
			
		||||
  drag_grab->drag_start_y = stage_pos.y;
 | 
			
		||||
 | 
			
		||||
  g_object_weak_ref (G_OBJECT (source),
 | 
			
		||||
                     drag_grab_data_source_destroyed,
 | 
			
		||||
                     drag_grab);
 | 
			
		||||
  modifiers = clutter_input_device_get_modifier_state (seat->pointer.device);
 | 
			
		||||
  drag_grab->buttons = modifiers &
 | 
			
		||||
    (CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK |
 | 
			
		||||
     CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK);
 | 
			
		||||
 | 
			
		||||
  drag_grab->drag_data_source = source;
 | 
			
		||||
  meta_wayland_drag_grab_set_source (drag_grab, source);
 | 
			
		||||
  meta_wayland_data_device_set_dnd_source (data_device,
 | 
			
		||||
                                           drag_grab->drag_data_source);
 | 
			
		||||
  data_source_update_user_dnd_action (source, modifiers);
 | 
			
		||||
 | 
			
		||||
  if (icon_surface)
 | 
			
		||||
    {
 | 
			
		||||
@@ -480,8 +915,7 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice                 *data
 | 
			
		||||
                                                      drag_grab->drag_start_x,
 | 
			
		||||
                                                      drag_grab->drag_start_y);
 | 
			
		||||
      meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
 | 
			
		||||
                                      -drag_grab->drag_surface->offset_x,
 | 
			
		||||
                                      -drag_grab->drag_surface->offset_y);
 | 
			
		||||
                                      0, 0);
 | 
			
		||||
      clutter_actor_add_child (drag_grab->feedback_actor,
 | 
			
		||||
                               CLUTTER_ACTOR (drag_grab->drag_surface->surface_actor));
 | 
			
		||||
 | 
			
		||||
@@ -490,6 +924,7 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice                 *data
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*) drag_grab);
 | 
			
		||||
  meta_wayland_data_source_set_seat (source, seat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -548,6 +983,10 @@ data_device_start_drag (struct wl_client *client,
 | 
			
		||||
  meta_wayland_data_device_start_drag (data_device, client,
 | 
			
		||||
                                       &drag_grab_interface,
 | 
			
		||||
                                       surface, drag_source, icon_surface);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_keyboard_set_focus (&seat->keyboard, NULL);
 | 
			
		||||
  meta_wayland_keyboard_start_grab (&seat->keyboard,
 | 
			
		||||
                                    &seat->data_device.current_grab->keyboard_grab);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -600,6 +1039,47 @@ meta_wayland_source_cancel (MetaWaylandDataSource *source)
 | 
			
		||||
  wl_data_source_send_cancelled (source_wayland->resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_source_action (MetaWaylandDataSource                  *source,
 | 
			
		||||
                            enum wl_data_device_manager_dnd_action  action)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourceWayland *source_wayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_WAYLAND (source);
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_get_version (source_wayland->resource) >=
 | 
			
		||||
      WL_DATA_SOURCE_ACTION_SINCE_VERSION)
 | 
			
		||||
    wl_data_source_send_action (source_wayland->resource, action);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourceWayland *source_wayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_WAYLAND (source);
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_get_version (source_wayland->resource) >=
 | 
			
		||||
      WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
 | 
			
		||||
    wl_data_source_send_dnd_drop_performed (source_wayland->resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourceWayland *source_wayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_WAYLAND (source);
 | 
			
		||||
  enum wl_data_device_manager_dnd_action action;
 | 
			
		||||
 | 
			
		||||
  if (meta_wayland_source_get_in_ask (source))
 | 
			
		||||
    {
 | 
			
		||||
      action = meta_wayland_data_source_get_current_action (source);
 | 
			
		||||
      meta_wayland_source_action (source, action);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_get_version (source_wayland->resource) >=
 | 
			
		||||
      WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
 | 
			
		||||
    wl_data_source_send_dnd_finished (source_wayland->resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_source_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
@@ -623,6 +1103,9 @@ meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *
 | 
			
		||||
  data_source_class->send = meta_wayland_source_send;
 | 
			
		||||
  data_source_class->target = meta_wayland_source_target;
 | 
			
		||||
  data_source_class->cancel = meta_wayland_source_cancel;
 | 
			
		||||
  data_source_class->action = meta_wayland_source_action;
 | 
			
		||||
  data_source_class->drop_performed = meta_wayland_source_drop_performed;
 | 
			
		||||
  data_source_class->drag_finished = meta_wayland_source_drag_finished;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -647,6 +1130,7 @@ meta_wayland_data_source_init (MetaWaylandDataSource *source)
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
  wl_array_init (&priv->mime_types);
 | 
			
		||||
  priv->current_dnd_action = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -665,6 +1149,7 @@ meta_wayland_drag_dest_focus_in (MetaWaylandDataDevice *data_device,
 | 
			
		||||
  MetaWaylandDragGrab *grab = data_device->current_grab;
 | 
			
		||||
  struct wl_display *display;
 | 
			
		||||
  struct wl_client *client;
 | 
			
		||||
  uint32_t source_actions;
 | 
			
		||||
  wl_fixed_t sx, sy;
 | 
			
		||||
 | 
			
		||||
  if (!grab->drag_focus_data_device)
 | 
			
		||||
@@ -677,6 +1162,13 @@ meta_wayland_drag_dest_focus_in (MetaWaylandDataDevice *data_device,
 | 
			
		||||
  wl_resource_add_destroy_listener (grab->drag_focus_data_device,
 | 
			
		||||
                                    &grab->drag_focus_listener);
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_get_version (offer->resource) >=
 | 
			
		||||
      WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION)
 | 
			
		||||
    {
 | 
			
		||||
      source_actions = meta_wayland_data_source_get_actions (offer->source);
 | 
			
		||||
      wl_data_offer_send_source_actions (offer->resource, source_actions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_get_relative_coordinates (grab->generic.pointer,
 | 
			
		||||
                                                 surface, &sx, &sy);
 | 
			
		||||
  wl_data_device_send_enter (grab->drag_focus_data_device,
 | 
			
		||||
@@ -722,11 +1214,18 @@ meta_wayland_drag_dest_drop (MetaWaylandDataDevice *data_device,
 | 
			
		||||
  wl_data_device_send_drop (grab->drag_focus_data_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_drag_dest_update (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                               MetaWaylandSurface    *surface)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandDragDestFuncs meta_wayland_drag_dest_funcs = {
 | 
			
		||||
  meta_wayland_drag_dest_focus_in,
 | 
			
		||||
  meta_wayland_drag_dest_focus_out,
 | 
			
		||||
  meta_wayland_drag_dest_motion,
 | 
			
		||||
  meta_wayland_drag_dest_drop
 | 
			
		||||
  meta_wayland_drag_dest_drop,
 | 
			
		||||
  meta_wayland_drag_dest_update
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const MetaWaylandDragDestFuncs *
 | 
			
		||||
@@ -815,6 +1314,7 @@ data_device_set_selection (struct wl_client *client,
 | 
			
		||||
                           guint32 serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv;
 | 
			
		||||
  MetaWaylandDataSource *source;
 | 
			
		||||
 | 
			
		||||
  if (source_resource)
 | 
			
		||||
@@ -822,6 +1322,19 @@ data_device_set_selection (struct wl_client *client,
 | 
			
		||||
  else
 | 
			
		||||
    source = NULL;
 | 
			
		||||
 | 
			
		||||
  if (source)
 | 
			
		||||
    {
 | 
			
		||||
      priv = meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
 | 
			
		||||
      if (priv->actions_set)
 | 
			
		||||
        {
 | 
			
		||||
          wl_resource_post_error(source_resource,
 | 
			
		||||
                                 WL_DATA_SOURCE_ERROR_INVALID_SOURCE,
 | 
			
		||||
                                 "cannot set drag-and-drop source as selection");
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* FIXME: Store serial and check against incoming serial here. */
 | 
			
		||||
  meta_wayland_data_device_set_selection (data_device, source, serial);
 | 
			
		||||
}
 | 
			
		||||
@@ -943,30 +1456,12 @@ meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
 | 
			
		||||
    data_device->current_grab->drag_surface == surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDragGrab *drag_grab;
 | 
			
		||||
 | 
			
		||||
  if (!data_device->current_grab)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  drag_grab = data_device->current_grab;
 | 
			
		||||
 | 
			
		||||
  if (!drag_grab->feedback_actor || !drag_grab->drag_surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_feedback_actor_set_anchor (META_FEEDBACK_ACTOR (drag_grab->feedback_actor),
 | 
			
		||||
                                  -drag_grab->drag_surface->offset_x,
 | 
			
		||||
                                  -drag_grab->drag_surface->offset_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source,
 | 
			
		||||
                                        const gchar                 *mime_type)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourcePrivate *priv =
 | 
			
		||||
    meta_wayland_data_source_get_instance_private (source);
 | 
			
		||||
    meta_wayland_data_source_get_instance_private ((MetaWaylandDataSource *)source);
 | 
			
		||||
  gchar **p;
 | 
			
		||||
 | 
			
		||||
  wl_array_for_each (p, &priv->mime_types)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,11 @@ struct _MetaWaylandDataSourceClass
 | 
			
		||||
  void (* target)  (MetaWaylandDataSource *source,
 | 
			
		||||
                    const gchar           *mime_type);
 | 
			
		||||
  void (* cancel)  (MetaWaylandDataSource *source);
 | 
			
		||||
 | 
			
		||||
  void (* action)         (MetaWaylandDataSource *source,
 | 
			
		||||
                           uint32_t               action);
 | 
			
		||||
  void (* drop_performed) (MetaWaylandDataSource *source);
 | 
			
		||||
  void (* drag_finished)  (MetaWaylandDataSource *source);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandDataDevice
 | 
			
		||||
@@ -69,7 +74,6 @@ void meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_de
 | 
			
		||||
 | 
			
		||||
gboolean meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                                                  MetaWaylandSurface    *surface);
 | 
			
		||||
void meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_data_device_set_dnd_source     (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                                                  MetaWaylandDataSource *source);
 | 
			
		||||
@@ -95,6 +99,17 @@ void     meta_wayland_data_source_send           (MetaWaylandDataSource *source,
 | 
			
		||||
                                                  const gchar           *mime_type,
 | 
			
		||||
                                                  gint                   fd);
 | 
			
		||||
 | 
			
		||||
void     meta_wayland_data_source_notify_finish  (MetaWaylandDataSource *source);
 | 
			
		||||
 | 
			
		||||
uint32_t meta_wayland_data_source_get_actions        (MetaWaylandDataSource *source);
 | 
			
		||||
uint32_t meta_wayland_data_source_get_user_action    (MetaWaylandDataSource *source);
 | 
			
		||||
uint32_t meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source);
 | 
			
		||||
 | 
			
		||||
void     meta_wayland_data_source_set_actions        (MetaWaylandDataSource *source,
 | 
			
		||||
                                                      uint32_t               dnd_actions);
 | 
			
		||||
void     meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
 | 
			
		||||
                                                      uint32_t               action);
 | 
			
		||||
 | 
			
		||||
const MetaWaylandDragDestFuncs *
 | 
			
		||||
         meta_wayland_data_device_get_drag_dest_funcs (void);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -56,13 +56,19 @@
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <clutter/evdev/clutter-evdev.h>
 | 
			
		||||
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void meta_wayland_keyboard_update_xkb_state (MetaWaylandKeyboard *keyboard);
 | 
			
		||||
static void notify_modifiers (MetaWaylandKeyboard *keyboard);
 | 
			
		||||
static guint evdev_code (const ClutterKeyEvent *event);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
unbind_resource (struct wl_resource *resource)
 | 
			
		||||
@@ -240,8 +246,10 @@ keyboard_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
notify_key (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
            uint32_t time, uint32_t key, uint32_t state)
 | 
			
		||||
meta_wayland_keyboard_broadcast_key (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                     uint32_t             time,
 | 
			
		||||
                                     uint32_t             key,
 | 
			
		||||
                                     uint32_t             state)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  struct wl_list *l;
 | 
			
		||||
@@ -251,11 +259,12 @@ notify_key (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      uint32_t serial = wl_display_next_serial (display);
 | 
			
		||||
 | 
			
		||||
      keyboard->key_serial = wl_display_next_serial (display);
 | 
			
		||||
 | 
			
		||||
      wl_resource_for_each (resource, l)
 | 
			
		||||
        {
 | 
			
		||||
          wl_keyboard_send_key (resource, serial, time, key, state);
 | 
			
		||||
          wl_keyboard_send_key (resource, keyboard->key_serial, time, key, state);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -263,8 +272,15 @@ notify_key (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
  return (keyboard->focus_surface != NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
notify_key (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
            const ClutterEvent  *event)
 | 
			
		||||
{
 | 
			
		||||
  return keyboard->grab->interface->key (keyboard->grab, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
notify_modifiers (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
meta_wayland_keyboard_broadcast_modifiers (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  struct xkb_state *state;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
@@ -289,6 +305,16 @@ notify_modifiers (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
notify_modifiers (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  struct xkb_state *state;
 | 
			
		||||
 | 
			
		||||
  state = keyboard->xkb_info.state;
 | 
			
		||||
  keyboard->grab->interface->modifiers (keyboard->grab,
 | 
			
		||||
                                        xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_keyboard_update_xkb_state (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
@@ -368,6 +394,45 @@ settings_changed (GSettings           *settings,
 | 
			
		||||
  notify_key_repeat (keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
default_grab_key (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                  const ClutterEvent      *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandKeyboard *keyboard = grab->keyboard;
 | 
			
		||||
  gboolean is_press = event->type == CLUTTER_KEY_PRESS;
 | 
			
		||||
  guint32 code;
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Synthetic key events are for autorepeat. Ignore those, as
 | 
			
		||||
   * autorepeat in Wayland is done on the client side. */
 | 
			
		||||
  if (event->key.flags & CLUTTER_EVENT_FLAG_SYNTHETIC)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  if (META_IS_BACKEND_NATIVE (backend))
 | 
			
		||||
    code = clutter_evdev_event_get_event_code (event);
 | 
			
		||||
  else
 | 
			
		||||
#endif
 | 
			
		||||
    code = evdev_code (&event->key);
 | 
			
		||||
 | 
			
		||||
  return meta_wayland_keyboard_broadcast_key (keyboard, event->key.time,
 | 
			
		||||
                                              code, is_press);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
default_grab_modifiers (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                        ClutterModifierType      modifiers)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_keyboard_broadcast_modifiers (grab->keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandKeyboardGrabInterface default_keyboard_grab_interface = {
 | 
			
		||||
  default_grab_key,
 | 
			
		||||
  default_grab_modifiers
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                            struct wl_display   *display)
 | 
			
		||||
@@ -385,6 +450,10 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
 | 
			
		||||
  keyboard->xkb_info.keymap_fd = -1;
 | 
			
		||||
 | 
			
		||||
  keyboard->default_grab.interface = &default_keyboard_grab_interface;
 | 
			
		||||
  keyboard->default_grab.keyboard = keyboard;
 | 
			
		||||
  keyboard->grab = &keyboard->default_grab;
 | 
			
		||||
 | 
			
		||||
  keyboard->settings = g_settings_new ("org.gnome.desktop.peripherals.keyboard");
 | 
			
		||||
  g_signal_connect (keyboard->settings, "changed",
 | 
			
		||||
                    G_CALLBACK (settings_changed), keyboard);
 | 
			
		||||
@@ -461,7 +530,7 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
		is_press ? "press" : "release",
 | 
			
		||||
		event->hardware_keycode);
 | 
			
		||||
 | 
			
		||||
  handled = notify_key (keyboard, event->time, evdev_code (event), is_press);
 | 
			
		||||
  handled = notify_key (keyboard, (const ClutterEvent *) event);
 | 
			
		||||
 | 
			
		||||
  if (handled)
 | 
			
		||||
    meta_verbose ("Sent event to wayland client\n");
 | 
			
		||||
@@ -672,3 +741,25 @@ meta_wayland_keyboard_create_new_resource (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
      wl_list_insert (&keyboard->resource_list, wl_resource_get_link (cr));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_keyboard_can_popup (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                 uint32_t             serial)
 | 
			
		||||
{
 | 
			
		||||
  return keyboard->key_serial == serial;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard     *keyboard,
 | 
			
		||||
                                  MetaWaylandKeyboardGrab *grab)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_keyboard_set_focus (keyboard, NULL);
 | 
			
		||||
  keyboard->grab = grab;
 | 
			
		||||
  grab->keyboard = keyboard;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
  keyboard->grab = &keyboard->default_grab;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,20 @@
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include <xkbcommon/xkbcommon.h>
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandKeyboardGrabInterface
 | 
			
		||||
{
 | 
			
		||||
  gboolean (*key)       (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                         const ClutterEvent      *event);
 | 
			
		||||
  void     (*modifiers) (MetaWaylandKeyboardGrab *grab,
 | 
			
		||||
                         ClutterModifierType      modifiers);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandKeyboardGrab
 | 
			
		||||
{
 | 
			
		||||
  const MetaWaylandKeyboardGrabInterface *interface;
 | 
			
		||||
  MetaWaylandKeyboard *keyboard;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  struct xkb_keymap *keymap;
 | 
			
		||||
@@ -68,10 +82,14 @@ struct _MetaWaylandKeyboard
 | 
			
		||||
  MetaWaylandSurface *focus_surface;
 | 
			
		||||
  struct wl_listener focus_surface_listener;
 | 
			
		||||
  uint32_t focus_serial;
 | 
			
		||||
  uint32_t key_serial;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandXkbInfo xkb_info;
 | 
			
		||||
  enum xkb_state_component mods_changed;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandKeyboardGrab *grab;
 | 
			
		||||
  MetaWaylandKeyboardGrab default_grab;
 | 
			
		||||
 | 
			
		||||
  GSettings *settings;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -100,4 +118,11 @@ void meta_wayland_keyboard_create_new_resource (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                                struct wl_resource  *seat_resource,
 | 
			
		||||
                                                uint32_t id);
 | 
			
		||||
 | 
			
		||||
gboolean meta_wayland_keyboard_can_popup (MetaWaylandKeyboard *keyboard,
 | 
			
		||||
                                          uint32_t             serial);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_keyboard_start_grab (MetaWaylandKeyboard     *keyboard,
 | 
			
		||||
                                       MetaWaylandKeyboardGrab *grab);
 | 
			
		||||
void meta_wayland_keyboard_end_grab   (MetaWaylandKeyboard     *keyboard);
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_KEYBOARD_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ bind_output (struct wl_client *client,
 | 
			
		||||
                       mode_flags,
 | 
			
		||||
                       (int)monitor_info->rect.width,
 | 
			
		||||
                       (int)monitor_info->rect.height,
 | 
			
		||||
                       (int)monitor_info->refresh_rate);
 | 
			
		||||
                       (int)(monitor_info->refresh_rate * 1000));
 | 
			
		||||
 | 
			
		||||
  if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
 | 
			
		||||
    wl_output_send_scale (resource, output->scale);
 | 
			
		||||
@@ -160,7 +160,7 @@ wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
 | 
			
		||||
                           mode_flags,
 | 
			
		||||
                           (int)monitor_info->rect.width,
 | 
			
		||||
                           (int)monitor_info->rect.height,
 | 
			
		||||
                           (int)monitor_info->refresh_rate);
 | 
			
		||||
                           (int)(monitor_info->refresh_rate * 1000));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* It's very important that we change the output pointer here, as
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										818
									
								
								src/wayland/meta-wayland-pointer-constraints.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										818
									
								
								src/wayland/meta-wayland-pointer-constraints.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,818 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-pointer-constraints.h"
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include "meta/meta-backend.h"
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-wayland-seat.h"
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
#include "meta-wayland-surface.h"
 | 
			
		||||
#include "meta-wayland-region.h"
 | 
			
		||||
#include "meta-pointer-lock-wayland.h"
 | 
			
		||||
#include "meta-pointer-confinement-wayland.h"
 | 
			
		||||
#include "window-private.h"
 | 
			
		||||
#include "backends/meta-backend-private.h"
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#include "backends/meta-pointer-constraint.h"
 | 
			
		||||
 | 
			
		||||
#include "pointer-constraints-unstable-v1-server-protocol.h"
 | 
			
		||||
 | 
			
		||||
static GQuark quark_pending_constraint_state = 0;
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandPointerConstraint
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
  gboolean is_enabled;
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  MetaWaylandPointerGrab grab;
 | 
			
		||||
  MetaWaylandSeat *seat;
 | 
			
		||||
  enum zwp_pointer_constraints_v1_lifetime lifetime;
 | 
			
		||||
 | 
			
		||||
  gboolean hint_set;
 | 
			
		||||
  wl_fixed_t x_hint;
 | 
			
		||||
  wl_fixed_t y_hint;
 | 
			
		||||
 | 
			
		||||
  MetaPointerConstraint *constraint;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint;
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
  gulong applied_handler_id;
 | 
			
		||||
} MetaWaylandPendingConstraintState;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GList *pending_constraint_states;
 | 
			
		||||
} MetaWaylandPendingConstraintStateContainer;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaWaylandPointerConstraint, meta_wayland_pointer_constraint,
 | 
			
		||||
               G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
static const struct zwp_locked_pointer_v1_interface locked_pointer_interface;
 | 
			
		||||
static const struct zwp_confined_pointer_v1_interface confined_pointer_interface;
 | 
			
		||||
static const MetaWaylandPointerGrabInterface locked_pointer_grab_interface;
 | 
			
		||||
static const MetaWaylandPointerGrabInterface confined_pointer_grab_interface;
 | 
			
		||||
 | 
			
		||||
static cairo_region_t *
 | 
			
		||||
create_infinite_constraint_region (void)
 | 
			
		||||
{
 | 
			
		||||
  return cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
 | 
			
		||||
                                          .x = INT_MIN / 2,
 | 
			
		||||
                                          .y = INT_MIN / 2,
 | 
			
		||||
                                          .width = INT_MAX,
 | 
			
		||||
                                          .height = INT_MAX,
 | 
			
		||||
                                        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandPointerConstraint *
 | 
			
		||||
meta_wayland_pointer_constraint_new (MetaWaylandSurface                      *surface,
 | 
			
		||||
                                     MetaWaylandSeat                         *seat,
 | 
			
		||||
                                     MetaWaylandRegion                       *region,
 | 
			
		||||
                                     enum zwp_pointer_constraints_v1_lifetime lifetime,
 | 
			
		||||
                                     struct wl_resource                      *resource,
 | 
			
		||||
                                     const MetaWaylandPointerGrabInterface   *grab_interface)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint;
 | 
			
		||||
 | 
			
		||||
  constraint = g_object_new (META_TYPE_WAYLAND_POINTER_CONSTRAINT, NULL);
 | 
			
		||||
  if (!constraint)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  constraint->surface = surface;
 | 
			
		||||
  constraint->seat = seat;
 | 
			
		||||
  constraint->lifetime = lifetime;
 | 
			
		||||
  constraint->resource = resource;
 | 
			
		||||
  constraint->grab.interface = grab_interface;
 | 
			
		||||
 | 
			
		||||
  if (region)
 | 
			
		||||
    {
 | 
			
		||||
      constraint->region =
 | 
			
		||||
        cairo_region_copy (meta_wayland_region_peek_cairo_region (region));
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      constraint->region = create_infinite_constraint_region ();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return constraint;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
meta_wayland_pointer_constraint_is_enabled (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  return constraint->is_enabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_notify_activated (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource = constraint->resource;
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_instance_of (resource,
 | 
			
		||||
                               &zwp_locked_pointer_v1_interface,
 | 
			
		||||
                               &locked_pointer_interface))
 | 
			
		||||
    {
 | 
			
		||||
      zwp_locked_pointer_v1_send_locked (resource);
 | 
			
		||||
    }
 | 
			
		||||
  else if (wl_resource_instance_of (resource,
 | 
			
		||||
                                    &zwp_confined_pointer_v1_interface,
 | 
			
		||||
                                    &confined_pointer_interface))
 | 
			
		||||
    {
 | 
			
		||||
      zwp_confined_pointer_v1_send_confined (resource);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource = constraint->resource;
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_instance_of (resource,
 | 
			
		||||
                               &zwp_locked_pointer_v1_interface,
 | 
			
		||||
                               &locked_pointer_interface))
 | 
			
		||||
    zwp_locked_pointer_v1_send_unlocked (resource);
 | 
			
		||||
  else if (wl_resource_instance_of (resource,
 | 
			
		||||
                                    &zwp_confined_pointer_v1_interface,
 | 
			
		||||
                                    &confined_pointer_interface))
 | 
			
		||||
    zwp_confined_pointer_v1_send_unconfined (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaPointerConstraint *
 | 
			
		||||
meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource = constraint->resource;
 | 
			
		||||
 | 
			
		||||
  if (wl_resource_instance_of (resource,
 | 
			
		||||
                               &zwp_locked_pointer_v1_interface,
 | 
			
		||||
                               &locked_pointer_interface))
 | 
			
		||||
    {
 | 
			
		||||
      return meta_pointer_lock_wayland_new ();
 | 
			
		||||
    }
 | 
			
		||||
  else if (wl_resource_instance_of (resource,
 | 
			
		||||
                                    &zwp_confined_pointer_v1_interface,
 | 
			
		||||
                                    &confined_pointer_interface))
 | 
			
		||||
    {
 | 
			
		||||
      return meta_pointer_confinement_wayland_new (constraint);
 | 
			
		||||
    }
 | 
			
		||||
  g_assert_not_reached ();
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
 | 
			
		||||
  g_assert (!constraint->is_enabled);
 | 
			
		||||
 | 
			
		||||
  constraint->is_enabled = TRUE;
 | 
			
		||||
  meta_wayland_pointer_constraint_notify_activated (constraint);
 | 
			
		||||
  meta_wayland_pointer_start_grab (&constraint->seat->pointer,
 | 
			
		||||
                                   &constraint->grab);
 | 
			
		||||
 | 
			
		||||
  constraint->constraint =
 | 
			
		||||
    meta_wayland_pointer_constraint_create_pointer_constraint (constraint);
 | 
			
		||||
  meta_backend_set_client_pointer_constraint (backend, constraint->constraint);
 | 
			
		||||
  g_object_add_weak_pointer (G_OBJECT (constraint->constraint),
 | 
			
		||||
                             (gpointer *) &constraint->constraint);
 | 
			
		||||
  g_object_unref (constraint->constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_pointer_constraint_notify_deactivated (constraint);
 | 
			
		||||
  meta_wayland_pointer_end_grab (constraint->grab.pointer);
 | 
			
		||||
  meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_constraint_destroy (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  if (meta_wayland_pointer_constraint_is_enabled (constraint))
 | 
			
		||||
    meta_wayland_pointer_constraint_disable (constraint);
 | 
			
		||||
 | 
			
		||||
  wl_resource_set_user_data (constraint->resource, NULL);
 | 
			
		||||
  cairo_region_destroy (constraint->region);
 | 
			
		||||
  g_object_unref (constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
is_within_constraint_region (MetaWaylandPointerConstraint *constraint,
 | 
			
		||||
                             wl_fixed_t                    sx,
 | 
			
		||||
                             wl_fixed_t                    sy)
 | 
			
		||||
{
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
  gboolean is_within;
 | 
			
		||||
 | 
			
		||||
  region = meta_wayland_pointer_constraint_calculate_effective_region (constraint);
 | 
			
		||||
  is_within = cairo_region_contains_point (constraint->region,
 | 
			
		||||
                                           wl_fixed_to_int (sx),
 | 
			
		||||
                                           wl_fixed_to_int (sy));
 | 
			
		||||
  cairo_region_destroy (region);
 | 
			
		||||
 | 
			
		||||
  return is_within;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_constraint_maybe_enable (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = constraint->seat;
 | 
			
		||||
  wl_fixed_t sx, sy;
 | 
			
		||||
 | 
			
		||||
  if (constraint->is_enabled)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (seat->keyboard.focus_surface != constraint->surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_get_relative_coordinates (&constraint->seat->pointer,
 | 
			
		||||
                                                 constraint->surface,
 | 
			
		||||
                                                 &sx, &sy);
 | 
			
		||||
  if (!is_within_constraint_region (constraint, sx, sy))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_constraint_enable (constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_remove (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = constraint->surface;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_surface_remove_pointer_constraint (surface, constraint);
 | 
			
		||||
  meta_wayland_pointer_constraint_destroy (constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_constraint_maybe_remove_for_seat (MetaWaylandSeat *seat,
 | 
			
		||||
                                                       MetaWindow      *focus_window)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = &seat->pointer;
 | 
			
		||||
 | 
			
		||||
  if ((pointer->grab->interface == &confined_pointer_grab_interface ||
 | 
			
		||||
       pointer->grab->interface == &locked_pointer_grab_interface) &&
 | 
			
		||||
      pointer->focus_surface &&
 | 
			
		||||
      pointer->focus_surface->window != focus_window)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
        wl_container_of (pointer->grab, constraint, grab);
 | 
			
		||||
 | 
			
		||||
      switch (constraint->lifetime)
 | 
			
		||||
        {
 | 
			
		||||
        case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
 | 
			
		||||
          meta_wayland_pointer_constraint_remove (constraint);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
 | 
			
		||||
          meta_wayland_pointer_constraint_disable (constraint);
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
          g_assert_not_reached ();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_constraint_maybe_enable_for_window (MetaWindow *window)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = window->surface;
 | 
			
		||||
  GList *it;
 | 
			
		||||
 | 
			
		||||
  for (it = surface->pointer_constraints; it; it = it->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandPointerConstraint *constraint = it->data;
 | 
			
		||||
 | 
			
		||||
      meta_wayland_pointer_constraint_maybe_enable (constraint);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandSeat *
 | 
			
		||||
meta_wayland_pointer_constraint_get_seat (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  return constraint->seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cairo_region_t *
 | 
			
		||||
meta_wayland_pointer_constraint_calculate_effective_region (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  cairo_region_t *region;
 | 
			
		||||
 | 
			
		||||
  region = cairo_region_copy (constraint->surface->input_region);
 | 
			
		||||
  cairo_region_intersect (region, constraint->region);
 | 
			
		||||
 | 
			
		||||
  return region;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cairo_region_t *
 | 
			
		||||
meta_wayland_pointer_constraint_get_region (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  return constraint->region;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandSurface *
 | 
			
		||||
meta_wayland_pointer_constraint_get_surface (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  return constraint->surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_constraint_resource_destroyed (struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
    wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  if (!constraint)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_constraint_remove (constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pending_constraint_state_free (MetaWaylandPendingConstraintState *constraint_pending)
 | 
			
		||||
{
 | 
			
		||||
  g_clear_pointer (&constraint_pending->region, cairo_region_destroy);
 | 
			
		||||
  if (constraint_pending->constraint)
 | 
			
		||||
    g_object_remove_weak_pointer (G_OBJECT (constraint_pending->constraint),
 | 
			
		||||
                                  (gpointer *) &constraint_pending->constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandPendingConstraintStateContainer *
 | 
			
		||||
get_pending_constraint_state_container (MetaWaylandPendingState *pending)
 | 
			
		||||
{
 | 
			
		||||
  return g_object_get_qdata (G_OBJECT (pending),
 | 
			
		||||
                             quark_pending_constraint_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandPendingConstraintState *
 | 
			
		||||
get_pending_constraint_state (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPendingState *pending = constraint->surface->pending;
 | 
			
		||||
  MetaWaylandPendingConstraintStateContainer *container;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  container = get_pending_constraint_state_container (pending);
 | 
			
		||||
  for (l = container->pending_constraint_states; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandPendingConstraintState *constraint_pending = l->data;
 | 
			
		||||
 | 
			
		||||
      if (constraint_pending->constraint == constraint)
 | 
			
		||||
        return constraint_pending;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pending_constraint_state_container_free (MetaWaylandPendingConstraintStateContainer *container)
 | 
			
		||||
{
 | 
			
		||||
  g_list_free_full (container->pending_constraint_states,
 | 
			
		||||
                    (GDestroyNotify) pending_constraint_state_free);
 | 
			
		||||
  g_free (container);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandPendingConstraintStateContainer *
 | 
			
		||||
ensure_pending_constraint_state_container (MetaWaylandPendingState *pending)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPendingConstraintStateContainer *container;
 | 
			
		||||
 | 
			
		||||
  container = get_pending_constraint_state_container (pending);
 | 
			
		||||
  if (!container)
 | 
			
		||||
    {
 | 
			
		||||
      container = g_new0 (MetaWaylandPendingConstraintStateContainer, 1);
 | 
			
		||||
      g_object_set_qdata_full (G_OBJECT (pending),
 | 
			
		||||
                               quark_pending_constraint_state,
 | 
			
		||||
                               container,
 | 
			
		||||
                               (GDestroyNotify) pending_constraint_state_container_free);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return container;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
remove_pending_constraint_state (MetaWaylandPointerConstraint *constraint,
 | 
			
		||||
                                 MetaWaylandPendingState      *pending)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPendingConstraintStateContainer *container;
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  container = get_pending_constraint_state_container (pending);
 | 
			
		||||
  for (l = container->pending_constraint_states; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandPendingConstraintState *constraint_pending = l->data;
 | 
			
		||||
      if (constraint_pending->constraint != constraint)
 | 
			
		||||
        continue;
 | 
			
		||||
 | 
			
		||||
      pending_constraint_state_free (l->data);
 | 
			
		||||
      container->pending_constraint_states =
 | 
			
		||||
        g_list_remove_link (container->pending_constraint_states, l);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pending_constraint_state_applied (MetaWaylandPendingState           *pending,
 | 
			
		||||
                                  MetaWaylandPendingConstraintState *constraint_pending)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint = constraint_pending->constraint;
 | 
			
		||||
 | 
			
		||||
  if (!constraint)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&constraint->region, cairo_region_destroy);
 | 
			
		||||
  if (constraint_pending->region)
 | 
			
		||||
    {
 | 
			
		||||
      constraint->region = constraint_pending->region;
 | 
			
		||||
      constraint_pending->region = NULL;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      constraint->region = create_infinite_constraint_region ();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_signal_handler_disconnect (pending,
 | 
			
		||||
                               constraint_pending->applied_handler_id);
 | 
			
		||||
  remove_pending_constraint_state (constraint, pending);
 | 
			
		||||
 | 
			
		||||
  /* The pointer is potentially warped by the actor paint signal callback if
 | 
			
		||||
   * the new region proved it necessary.
 | 
			
		||||
   */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandPendingConstraintState *
 | 
			
		||||
ensure_pending_constraint_state (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPendingState *pending = constraint->surface->pending;
 | 
			
		||||
  MetaWaylandPendingConstraintStateContainer *container;
 | 
			
		||||
  MetaWaylandPendingConstraintState *constraint_pending;
 | 
			
		||||
 | 
			
		||||
  container = ensure_pending_constraint_state_container (pending);
 | 
			
		||||
  constraint_pending = get_pending_constraint_state (constraint);
 | 
			
		||||
  if (!constraint_pending)
 | 
			
		||||
    {
 | 
			
		||||
      constraint_pending = g_new0 (MetaWaylandPendingConstraintState, 1);
 | 
			
		||||
      constraint_pending->constraint = constraint;
 | 
			
		||||
      constraint_pending->applied_handler_id =
 | 
			
		||||
        g_signal_connect (pending, "applied",
 | 
			
		||||
                          G_CALLBACK (pending_constraint_state_applied),
 | 
			
		||||
                          constraint_pending);
 | 
			
		||||
      g_object_add_weak_pointer (G_OBJECT (constraint),
 | 
			
		||||
                                 (gpointer *) &constraint_pending->constraint);
 | 
			
		||||
 | 
			
		||||
      container->pending_constraint_states =
 | 
			
		||||
        g_list_append (container->pending_constraint_states,
 | 
			
		||||
                       constraint_pending);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return constraint_pending;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_set_pending_region (MetaWaylandPointerConstraint *constraint,
 | 
			
		||||
                                                    MetaWaylandRegion            *region)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPendingConstraintState *constraint_pending;
 | 
			
		||||
 | 
			
		||||
  constraint_pending = ensure_pending_constraint_state (constraint);
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&constraint_pending->region, cairo_region_destroy);
 | 
			
		||||
  if (region)
 | 
			
		||||
    {
 | 
			
		||||
      constraint_pending->region =
 | 
			
		||||
        cairo_region_copy (meta_wayland_region_peek_cairo_region (region));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
init_pointer_constraint (struct wl_resource                      *resource,
 | 
			
		||||
                         uint32_t                                 id,
 | 
			
		||||
                         MetaWaylandSurface                      *surface,
 | 
			
		||||
                         MetaWaylandSeat                         *seat,
 | 
			
		||||
                         MetaWaylandRegion                       *region,
 | 
			
		||||
                         enum zwp_pointer_constraints_v1_lifetime lifetime,
 | 
			
		||||
                         const struct wl_interface               *interface,
 | 
			
		||||
                         const void                              *implementation,
 | 
			
		||||
                         const MetaWaylandPointerGrabInterface   *grab_interface)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_client *client = wl_resource_get_client (resource);
 | 
			
		||||
  struct wl_resource *cr;
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint;
 | 
			
		||||
 | 
			
		||||
  if (meta_wayland_surface_get_pointer_constraint_for_seat (surface, seat))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (resource,
 | 
			
		||||
                              WL_DISPLAY_ERROR_INVALID_OBJECT,
 | 
			
		||||
                              "the pointer as already requested to be "
 | 
			
		||||
                              "locked or confined on that surface");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  cr = wl_resource_create (client, interface,
 | 
			
		||||
                           wl_resource_get_version (resource),
 | 
			
		||||
                           id);
 | 
			
		||||
  if (cr == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      wl_client_post_no_memory (client);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  constraint = meta_wayland_pointer_constraint_new (surface, seat,
 | 
			
		||||
                                                    region,
 | 
			
		||||
                                                    lifetime,
 | 
			
		||||
                                                    cr, grab_interface);
 | 
			
		||||
  if (constraint == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      wl_client_post_no_memory (client);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_surface_add_pointer_constraint (surface, constraint);
 | 
			
		||||
 | 
			
		||||
  wl_resource_set_implementation (cr, implementation, constraint,
 | 
			
		||||
                                  pointer_constraint_resource_destroyed);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_constraint_maybe_enable (constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
locked_pointer_destroy (struct wl_client   *client,
 | 
			
		||||
                        struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
    wl_resource_get_user_data (resource);
 | 
			
		||||
  gboolean warp_pointer = FALSE;
 | 
			
		||||
  int warp_x, warp_y;
 | 
			
		||||
 | 
			
		||||
  if (constraint && constraint->is_enabled && constraint->hint_set &&
 | 
			
		||||
      is_within_constraint_region (constraint,
 | 
			
		||||
                                   constraint->x_hint,
 | 
			
		||||
                                   constraint->y_hint))
 | 
			
		||||
    {
 | 
			
		||||
      float sx, sy;
 | 
			
		||||
      float x, y;
 | 
			
		||||
 | 
			
		||||
      sx = (float)wl_fixed_to_double (constraint->x_hint);
 | 
			
		||||
      sy = (float)wl_fixed_to_double (constraint->y_hint);
 | 
			
		||||
      meta_wayland_surface_get_absolute_coordinates (constraint->surface,
 | 
			
		||||
                                                     sx, sy,
 | 
			
		||||
                                                     &x, &y);
 | 
			
		||||
      warp_pointer = TRUE;
 | 
			
		||||
      warp_x = (int) x;
 | 
			
		||||
      warp_y = (int) y;
 | 
			
		||||
    }
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
 | 
			
		||||
  if (warp_pointer)
 | 
			
		||||
    meta_backend_warp_pointer (meta_get_backend (), warp_x, warp_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
locked_pointer_set_cursor_position_hint (struct wl_client   *client,
 | 
			
		||||
                                         struct wl_resource *resource,
 | 
			
		||||
                                         wl_fixed_t          surface_x,
 | 
			
		||||
                                         wl_fixed_t          surface_y)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
    wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  /* Ignore a set cursor hint that was already sent after the constraint
 | 
			
		||||
   * was cancelled. */
 | 
			
		||||
  if (!constraint->resource || constraint->resource != resource)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  constraint->hint_set = TRUE;
 | 
			
		||||
  constraint->x_hint = surface_x;
 | 
			
		||||
  constraint->y_hint = surface_y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
locked_pointer_set_region (struct wl_client   *client,
 | 
			
		||||
                           struct wl_resource *resource,
 | 
			
		||||
                           struct wl_resource *region_resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
    wl_resource_get_user_data (resource);
 | 
			
		||||
  MetaWaylandRegion *region =
 | 
			
		||||
    region_resource ? wl_resource_get_user_data (region_resource) : NULL;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_constraint_set_pending_region (constraint, region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_locked_pointer_v1_interface locked_pointer_interface = {
 | 
			
		||||
  locked_pointer_destroy,
 | 
			
		||||
  locked_pointer_set_cursor_position_hint,
 | 
			
		||||
  locked_pointer_set_region,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
locked_pointer_grab_pointer_focus (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                                   MetaWaylandSurface     *surface)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
locked_pointer_grab_pointer_motion (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                                    const ClutterEvent     *event)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_pointer_send_relative_motion (grab->pointer, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
locked_pointer_grab_pointer_button (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                                    const ClutterEvent     *event)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_pointer_send_button (grab->pointer, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandPointerGrabInterface locked_pointer_grab_interface = {
 | 
			
		||||
  locked_pointer_grab_pointer_focus,
 | 
			
		||||
  locked_pointer_grab_pointer_motion,
 | 
			
		||||
  locked_pointer_grab_pointer_button,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_constraints_destroy (struct wl_client   *client,
 | 
			
		||||
                             struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_constraints_lock_pointer (struct wl_client   *client,
 | 
			
		||||
                                  struct wl_resource *resource,
 | 
			
		||||
                                  uint32_t            id,
 | 
			
		||||
                                  struct wl_resource *surface_resource,
 | 
			
		||||
                                  struct wl_resource *pointer_resource,
 | 
			
		||||
                                  struct wl_resource *region_resource,
 | 
			
		||||
                                  uint32_t            lifetime)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
 | 
			
		||||
  MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
 | 
			
		||||
  MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
 | 
			
		||||
  MetaWaylandRegion *region =
 | 
			
		||||
    region_resource ? wl_resource_get_user_data (region_resource) : NULL;
 | 
			
		||||
 | 
			
		||||
  init_pointer_constraint (resource, id, surface, seat, region, lifetime,
 | 
			
		||||
                           &zwp_locked_pointer_v1_interface,
 | 
			
		||||
                           &locked_pointer_interface,
 | 
			
		||||
                           &locked_pointer_grab_interface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
confined_pointer_grab_pointer_focus (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                                     MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
confined_pointer_grab_pointer_motion (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                                      const ClutterEvent     *event)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
    wl_container_of (grab, constraint, grab);
 | 
			
		||||
  MetaWaylandPointer *pointer = grab->pointer;
 | 
			
		||||
 | 
			
		||||
  g_assert (pointer->focus_surface);
 | 
			
		||||
  g_assert (pointer->focus_surface == constraint->surface);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_send_motion (pointer, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
confined_pointer_grab_pointer_button (MetaWaylandPointerGrab *grab,
 | 
			
		||||
                                      const ClutterEvent     *event)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_pointer_send_button (grab->pointer, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandPointerGrabInterface confined_pointer_grab_interface = {
 | 
			
		||||
  confined_pointer_grab_pointer_focus,
 | 
			
		||||
  confined_pointer_grab_pointer_motion,
 | 
			
		||||
  confined_pointer_grab_pointer_button,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
confined_pointer_destroy (struct wl_client   *client,
 | 
			
		||||
                          struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
confined_pointer_set_region (struct wl_client   *client,
 | 
			
		||||
                             struct wl_resource *resource,
 | 
			
		||||
                             struct wl_resource *region_resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointerConstraint *constraint =
 | 
			
		||||
    wl_resource_get_user_data (resource);
 | 
			
		||||
  MetaWaylandRegion *region =
 | 
			
		||||
    region_resource ? wl_resource_get_user_data (region_resource) : NULL;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_constraint_set_pending_region (constraint, region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_confined_pointer_v1_interface confined_pointer_interface = {
 | 
			
		||||
  confined_pointer_destroy,
 | 
			
		||||
  confined_pointer_set_region,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pointer_constraints_confine_pointer (struct wl_client   *client,
 | 
			
		||||
                                     struct wl_resource *resource,
 | 
			
		||||
                                     uint32_t            id,
 | 
			
		||||
                                     struct wl_resource *surface_resource,
 | 
			
		||||
                                     struct wl_resource *pointer_resource,
 | 
			
		||||
                                     struct wl_resource *region_resource,
 | 
			
		||||
                                     uint32_t            lifetime)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
 | 
			
		||||
  MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
 | 
			
		||||
  MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
 | 
			
		||||
  MetaWaylandRegion *region =
 | 
			
		||||
    region_resource ? wl_resource_get_user_data (region_resource) : NULL;
 | 
			
		||||
 | 
			
		||||
  init_pointer_constraint (resource, id, surface, seat, region, lifetime,
 | 
			
		||||
                           &zwp_confined_pointer_v1_interface,
 | 
			
		||||
                           &confined_pointer_interface,
 | 
			
		||||
                           &confined_pointer_grab_interface);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_pointer_constraints_v1_interface pointer_constraints = {
 | 
			
		||||
  pointer_constraints_destroy,
 | 
			
		||||
  pointer_constraints_lock_pointer,
 | 
			
		||||
  pointer_constraints_confine_pointer,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bind_pointer_constraints (struct wl_client *client,
 | 
			
		||||
                          void             *data,
 | 
			
		||||
                          uint32_t          version,
 | 
			
		||||
                          uint32_t          id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = data;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  resource = wl_resource_create (client,
 | 
			
		||||
                                 &zwp_pointer_constraints_v1_interface,
 | 
			
		||||
                                 1, id);
 | 
			
		||||
 | 
			
		||||
  wl_resource_set_implementation (resource,
 | 
			
		||||
                                  &pointer_constraints,
 | 
			
		||||
                                  compositor,
 | 
			
		||||
                                  NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_constraints_init (MetaWaylandCompositor *compositor)
 | 
			
		||||
{
 | 
			
		||||
  if (!wl_global_create (compositor->wayland_display,
 | 
			
		||||
                         &zwp_pointer_constraints_v1_interface, 1,
 | 
			
		||||
                         compositor, bind_pointer_constraints))
 | 
			
		||||
    g_error ("Could not create wp_pointer_constraints global");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_init (MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_constraint_class_init (MetaWaylandPointerConstraintClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  quark_pending_constraint_state =
 | 
			
		||||
    g_quark_from_static_string ("-meta-wayland-pointer-constraint-pending_state");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								src/wayland/meta-wayland-pointer-constraints.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/wayland/meta-wayland-pointer-constraints.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Red Hat
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by:
 | 
			
		||||
 *     Jonas Ådahl <jadahl@gmail.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef META_WAYLAND_POINTER_CONSTRAINTS_H
 | 
			
		||||
#define META_WAYLAND_POINTER_CONSTRAINTS_H
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-types.h"
 | 
			
		||||
#include "meta/window.h"
 | 
			
		||||
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_WAYLAND_POINTER_CONSTRAINT (meta_wayland_pointer_constraint_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaWaylandPointerConstraint,
 | 
			
		||||
                      meta_wayland_pointer_constraint,
 | 
			
		||||
                      META, WAYLAND_POINTER_CONSTRAINT,
 | 
			
		||||
                      GObject);
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandPointerConstraint MetaWaylandPointerConstraint;
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_constraints_init (MetaWaylandCompositor *compositor);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_constraint_maybe_enable (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_constraint_destroy (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
MetaWaylandSeat * meta_wayland_pointer_constraint_get_seat (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
cairo_region_t * meta_wayland_pointer_constraint_calculate_effective_region (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
cairo_region_t * meta_wayland_pointer_constraint_get_region (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
MetaWaylandSurface * meta_wayland_pointer_constraint_get_surface (MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_constraint_maybe_remove_for_seat (MetaWaylandSeat *seat,
 | 
			
		||||
                                                            MetaWindow      *focus_window);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_constraint_maybe_enable_for_window (MetaWindow *window);
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_POINTER_CONSTRAINTS_H */
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
#include "meta-wayland-pointer-gesture-pinch.h"
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
#include "meta-wayland-surface.h"
 | 
			
		||||
#include "pointer-gestures-server-protocol.h"
 | 
			
		||||
#include "pointer-gestures-unstable-v1-server-protocol.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_pinch_begin (MetaWaylandPointer *pointer,
 | 
			
		||||
@@ -45,10 +45,10 @@ handle_pinch_begin (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer_client->pinch_gesture_resources)
 | 
			
		||||
    {
 | 
			
		||||
      _wl_pointer_gesture_pinch_send_begin (resource, serial,
 | 
			
		||||
                                            clutter_event_get_time (event),
 | 
			
		||||
                                            pointer->focus_surface->resource,
 | 
			
		||||
                                            2);
 | 
			
		||||
      zwp_pointer_gesture_pinch_v1_send_begin (resource, serial,
 | 
			
		||||
                                               clutter_event_get_time (event),
 | 
			
		||||
                                               pointer->focus_surface->resource,
 | 
			
		||||
                                               2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -67,12 +67,12 @@ handle_pinch_update (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer_client->pinch_gesture_resources)
 | 
			
		||||
    {
 | 
			
		||||
      _wl_pointer_gesture_pinch_send_update (resource,
 | 
			
		||||
                                             clutter_event_get_time (event),
 | 
			
		||||
                                             wl_fixed_from_double (dx),
 | 
			
		||||
                                             wl_fixed_from_double (dy),
 | 
			
		||||
                                             wl_fixed_from_double (scale),
 | 
			
		||||
                                             wl_fixed_from_double (rotation));
 | 
			
		||||
      zwp_pointer_gesture_pinch_v1_send_update (resource,
 | 
			
		||||
                                                clutter_event_get_time (event),
 | 
			
		||||
                                                wl_fixed_from_double (dx),
 | 
			
		||||
                                                wl_fixed_from_double (dy),
 | 
			
		||||
                                                wl_fixed_from_double (scale),
 | 
			
		||||
                                                wl_fixed_from_double (rotation));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -93,9 +93,9 @@ handle_pinch_end (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer_client->pinch_gesture_resources)
 | 
			
		||||
    {
 | 
			
		||||
      _wl_pointer_gesture_pinch_send_end (resource, serial,
 | 
			
		||||
                                          clutter_event_get_time (event),
 | 
			
		||||
                                          cancelled);
 | 
			
		||||
      zwp_pointer_gesture_pinch_v1_send_end (resource, serial,
 | 
			
		||||
                                             clutter_event_get_time (event),
 | 
			
		||||
                                             cancelled);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -135,7 +135,7 @@ pointer_gesture_pinch_destroy (struct wl_client   *client,
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct _wl_pointer_gesture_pinch_interface pointer_gesture_pinch_interface = {
 | 
			
		||||
static const struct zwp_pointer_gesture_pinch_v1_interface pointer_gesture_pinch_interface = {
 | 
			
		||||
  pointer_gesture_pinch_destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -151,7 +151,7 @@ meta_wayland_pointer_gesture_pinch_create_new_resource (MetaWaylandPointer *poin
 | 
			
		||||
  pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
 | 
			
		||||
  g_return_if_fail (pointer_client != NULL);
 | 
			
		||||
 | 
			
		||||
  res = wl_resource_create (client, &_wl_pointer_gesture_pinch_interface,
 | 
			
		||||
  res = wl_resource_create (client, &zwp_pointer_gesture_pinch_v1_interface,
 | 
			
		||||
                            wl_resource_get_version (gestures_resource), id);
 | 
			
		||||
  wl_resource_set_implementation (res, &pointer_gesture_pinch_interface, pointer,
 | 
			
		||||
                                  meta_wayland_pointer_unbind_pointer_client_resource);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
#include "meta-wayland-pointer-gesture-swipe.h"
 | 
			
		||||
#include "meta-wayland-pointer.h"
 | 
			
		||||
#include "meta-wayland-surface.h"
 | 
			
		||||
#include "pointer-gestures-server-protocol.h"
 | 
			
		||||
#include "pointer-gestures-unstable-v1-server-protocol.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
handle_swipe_begin (MetaWaylandPointer *pointer,
 | 
			
		||||
@@ -46,10 +46,10 @@ handle_swipe_begin (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer_client->swipe_gesture_resources)
 | 
			
		||||
    {
 | 
			
		||||
      _wl_pointer_gesture_swipe_send_begin (resource, serial,
 | 
			
		||||
                                            clutter_event_get_time (event),
 | 
			
		||||
                                            pointer->focus_surface->resource,
 | 
			
		||||
                                            fingers);
 | 
			
		||||
      zwp_pointer_gesture_swipe_v1_send_begin (resource, serial,
 | 
			
		||||
                                               clutter_event_get_time (event),
 | 
			
		||||
                                               pointer->focus_surface->resource,
 | 
			
		||||
                                               fingers);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -66,10 +66,10 @@ handle_swipe_update (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer_client->swipe_gesture_resources)
 | 
			
		||||
    {
 | 
			
		||||
      _wl_pointer_gesture_swipe_send_update (resource,
 | 
			
		||||
                                             clutter_event_get_time (event),
 | 
			
		||||
                                             wl_fixed_from_double (dx),
 | 
			
		||||
                                             wl_fixed_from_double (dy));
 | 
			
		||||
      zwp_pointer_gesture_swipe_v1_send_update (resource,
 | 
			
		||||
                                                clutter_event_get_time (event),
 | 
			
		||||
                                                wl_fixed_from_double (dx),
 | 
			
		||||
                                                wl_fixed_from_double (dy));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -90,9 +90,9 @@ handle_swipe_end (MetaWaylandPointer *pointer,
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer_client->swipe_gesture_resources)
 | 
			
		||||
    {
 | 
			
		||||
      _wl_pointer_gesture_swipe_send_end (resource, serial,
 | 
			
		||||
                                          clutter_event_get_time (event),
 | 
			
		||||
                                          cancelled);
 | 
			
		||||
      zwp_pointer_gesture_swipe_v1_send_end (resource, serial,
 | 
			
		||||
                                             clutter_event_get_time (event),
 | 
			
		||||
                                             cancelled);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -131,7 +131,7 @@ pointer_gesture_swipe_release (struct wl_client   *client,
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct _wl_pointer_gesture_swipe_interface pointer_gesture_swipe_interface = {
 | 
			
		||||
static const struct zwp_pointer_gesture_swipe_v1_interface pointer_gesture_swipe_interface = {
 | 
			
		||||
  pointer_gesture_swipe_release
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -147,7 +147,7 @@ meta_wayland_pointer_gesture_swipe_create_new_resource (MetaWaylandPointer *poin
 | 
			
		||||
  pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
 | 
			
		||||
  g_return_if_fail (pointer_client != NULL);
 | 
			
		||||
 | 
			
		||||
  res = wl_resource_create (client, &_wl_pointer_gesture_swipe_interface,
 | 
			
		||||
  res = wl_resource_create (client, &zwp_pointer_gesture_swipe_v1_interface,
 | 
			
		||||
                            wl_resource_get_version (pointer_resource), id);
 | 
			
		||||
  wl_resource_set_implementation (res, &pointer_gesture_swipe_interface, pointer,
 | 
			
		||||
                                  meta_wayland_pointer_unbind_pointer_client_resource);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include "meta-wayland-pointer-gestures.h"
 | 
			
		||||
#include "pointer-gestures-server-protocol.h"
 | 
			
		||||
#include "pointer-gestures-unstable-v1-server-protocol.h"
 | 
			
		||||
#include "meta-wayland-versions.h"
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
 | 
			
		||||
@@ -53,7 +53,7 @@ gestures_get_pinch (struct wl_client   *client,
 | 
			
		||||
  meta_wayland_pointer_gesture_pinch_create_new_resource (pointer, client, resource, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct _wl_pointer_gestures_interface pointer_gestures_interface = {
 | 
			
		||||
static const struct zwp_pointer_gestures_v1_interface pointer_gestures_interface = {
 | 
			
		||||
  gestures_get_swipe,
 | 
			
		||||
  gestures_get_pinch
 | 
			
		||||
};
 | 
			
		||||
@@ -66,16 +66,8 @@ bind_pointer_gestures (struct wl_client *client,
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  resource = wl_resource_create (client, &_wl_pointer_gestures_interface, version, id);
 | 
			
		||||
 | 
			
		||||
  if (version != META__WL_POINTER_GESTURES_VERSION)
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (resource,
 | 
			
		||||
                              _WL_POINTER_GESTURES_ERROR_VERSION_MISMATCH,
 | 
			
		||||
                              "The client bound a non-supported version");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  resource = wl_resource_create (client, &zwp_pointer_gestures_v1_interface,
 | 
			
		||||
                                 version, id);
 | 
			
		||||
  wl_resource_set_implementation (resource, &pointer_gestures_interface,
 | 
			
		||||
                                  NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
@@ -84,7 +76,7 @@ void
 | 
			
		||||
meta_wayland_pointer_gestures_init (MetaWaylandCompositor *compositor)
 | 
			
		||||
{
 | 
			
		||||
  wl_global_create (compositor->wayland_display,
 | 
			
		||||
                    &_wl_pointer_gestures_interface,
 | 
			
		||||
                    META__WL_POINTER_GESTURES_VERSION,
 | 
			
		||||
                    &zwp_pointer_gestures_v1_interface,
 | 
			
		||||
                    META_ZWP_POINTER_GESTURES_V1_VERSION,
 | 
			
		||||
                    NULL, bind_pointer_gestures);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <clutter/clutter.h>
 | 
			
		||||
#include <clutter/evdev/clutter-evdev.h>
 | 
			
		||||
#include <cogl/cogl.h>
 | 
			
		||||
#include <cogl/cogl-wayland-server.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
@@ -62,6 +63,12 @@
 | 
			
		||||
#include "backends/meta-cursor-tracker-private.h"
 | 
			
		||||
#include "backends/meta-cursor-renderer.h"
 | 
			
		||||
 | 
			
		||||
#include "relative-pointer-unstable-v1-server-protocol.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
#include "backends/native/meta-backend-native.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
 | 
			
		||||
@@ -91,6 +98,7 @@ meta_wayland_pointer_client_new (void)
 | 
			
		||||
  wl_list_init (&pointer_client->pointer_resources);
 | 
			
		||||
  wl_list_init (&pointer_client->swipe_gesture_resources);
 | 
			
		||||
  wl_list_init (&pointer_client->pinch_gesture_resources);
 | 
			
		||||
  wl_list_init (&pointer_client->relative_pointer_resources);
 | 
			
		||||
 | 
			
		||||
  return pointer_client;
 | 
			
		||||
}
 | 
			
		||||
@@ -119,6 +127,11 @@ meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
 | 
			
		||||
      wl_list_remove (wl_resource_get_link (resource));
 | 
			
		||||
      wl_list_init (wl_resource_get_link (resource));
 | 
			
		||||
    }
 | 
			
		||||
  wl_resource_for_each_safe (resource, next, &pointer_client->relative_pointer_resources)
 | 
			
		||||
    {
 | 
			
		||||
      wl_list_remove (wl_resource_get_link (resource));
 | 
			
		||||
      wl_list_init (wl_resource_get_link (resource));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_slice_free (MetaWaylandPointerClient, pointer_client);
 | 
			
		||||
}
 | 
			
		||||
@@ -128,7 +141,8 @@ meta_wayland_pointer_client_is_empty (MetaWaylandPointerClient *pointer_client)
 | 
			
		||||
{
 | 
			
		||||
  return (wl_list_empty (&pointer_client->pointer_resources) &&
 | 
			
		||||
          wl_list_empty (&pointer_client->swipe_gesture_resources) &&
 | 
			
		||||
          wl_list_empty (&pointer_client->pinch_gesture_resources));
 | 
			
		||||
          wl_list_empty (&pointer_client->pinch_gesture_resources) &&
 | 
			
		||||
          wl_list_empty (&pointer_client->relative_pointer_resources));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandPointerClient *
 | 
			
		||||
@@ -237,26 +251,102 @@ pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
 | 
			
		||||
  meta_wayland_pointer_set_focus (pointer, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_send_frame (MetaWaylandPointer *pointer,
 | 
			
		||||
				 struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  if (wl_resource_get_version (resource) >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION)
 | 
			
		||||
    wl_pointer_send_frame (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_broadcast_frame (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  if (!pointer->focus_client)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
 | 
			
		||||
    {
 | 
			
		||||
      meta_wayland_pointer_send_frame (pointer, resource);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer,
 | 
			
		||||
                                           const ClutterEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  double dx, dy;
 | 
			
		||||
  double dx_unaccel, dy_unaccel;
 | 
			
		||||
  uint64_t time_us;
 | 
			
		||||
  uint32_t time_us_hi;
 | 
			
		||||
  uint32_t time_us_lo;
 | 
			
		||||
  wl_fixed_t dxf, dyf;
 | 
			
		||||
  wl_fixed_t dx_unaccelf, dy_unaccelf;
 | 
			
		||||
 | 
			
		||||
  if (!pointer->focus_client)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (!meta_backend_get_relative_motion_deltas (meta_get_backend (),
 | 
			
		||||
                                                event,
 | 
			
		||||
                                                &dx, &dy,
 | 
			
		||||
                                                &dx_unaccel, &dy_unaccel))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  time_us = clutter_evdev_event_get_time_usec (event);
 | 
			
		||||
  if (time_us == 0)
 | 
			
		||||
#endif
 | 
			
		||||
    time_us = clutter_event_get_time (event) * 1000ULL;
 | 
			
		||||
  time_us_hi = (uint32_t) (time_us >> 32);
 | 
			
		||||
  time_us_lo = (uint32_t) time_us;
 | 
			
		||||
  dxf = wl_fixed_from_double (dx);
 | 
			
		||||
  dyf = wl_fixed_from_double (dy);
 | 
			
		||||
  dx_unaccelf = wl_fixed_from_double (dx_unaccel);
 | 
			
		||||
  dy_unaccelf = wl_fixed_from_double (dy_unaccel);
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource,
 | 
			
		||||
                        &pointer->focus_client->relative_pointer_resources)
 | 
			
		||||
    {
 | 
			
		||||
      zwp_relative_pointer_v1_send_relative_motion (resource,
 | 
			
		||||
                                                    time_us_hi,
 | 
			
		||||
                                                    time_us_lo,
 | 
			
		||||
                                                    dxf,
 | 
			
		||||
                                                    dyf,
 | 
			
		||||
                                                    dx_unaccelf,
 | 
			
		||||
                                                    dy_unaccelf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
 | 
			
		||||
                                  const ClutterEvent *event)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  uint32_t time;
 | 
			
		||||
  wl_fixed_t sx, sy;
 | 
			
		||||
  float sx, sy;
 | 
			
		||||
 | 
			
		||||
  if (!pointer->focus_client)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  time = clutter_event_get_time (event);
 | 
			
		||||
  meta_wayland_pointer_get_relative_coordinates (pointer,
 | 
			
		||||
                                                 pointer->focus_surface,
 | 
			
		||||
  meta_wayland_surface_get_relative_coordinates (pointer->focus_surface,
 | 
			
		||||
                                                 event->motion.x,
 | 
			
		||||
                                                 event->motion.y,
 | 
			
		||||
                                                 &sx, &sy);
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
 | 
			
		||||
    {
 | 
			
		||||
      wl_pointer_send_motion (resource, time, sx, sy);
 | 
			
		||||
      wl_pointer_send_motion (resource, time,
 | 
			
		||||
                              wl_fixed_from_double (sx),
 | 
			
		||||
                              wl_fixed_from_double (sy));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_send_relative_motion (pointer, event);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_broadcast_frame (pointer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -277,26 +367,37 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
 | 
			
		||||
      uint32_t button;
 | 
			
		||||
      uint32_t serial;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
      MetaBackend *backend = meta_get_backend ();
 | 
			
		||||
      if (META_IS_BACKEND_NATIVE (backend))
 | 
			
		||||
        button = clutter_evdev_event_get_event_code (event);
 | 
			
		||||
      else
 | 
			
		||||
#endif
 | 
			
		||||
        {
 | 
			
		||||
          button = clutter_event_get_button (event);
 | 
			
		||||
          switch (button)
 | 
			
		||||
            {
 | 
			
		||||
            case 1:
 | 
			
		||||
              button = BTN_LEFT;
 | 
			
		||||
              break;
 | 
			
		||||
 | 
			
		||||
              /* 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 = button + (BTN_LEFT - 1) + 4;
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      time = clutter_event_get_time (event);
 | 
			
		||||
 | 
			
		||||
      button = clutter_event_get_button (event);
 | 
			
		||||
      switch (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 = button + BTN_LEFT - 1;
 | 
			
		||||
	  break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
 | 
			
		||||
      wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
 | 
			
		||||
@@ -305,6 +406,8 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
 | 
			
		||||
                                  time, button,
 | 
			
		||||
                                  event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_wayland_pointer_broadcast_frame (pointer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
 | 
			
		||||
@@ -494,26 +597,48 @@ handle_scroll_event (MetaWaylandPointer *pointer,
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
  wl_fixed_t x_value = 0, y_value = 0;
 | 
			
		||||
  int x_discrete = 0, y_discrete = 0;
 | 
			
		||||
  enum wl_pointer_axis_source source = -1;
 | 
			
		||||
 | 
			
		||||
  if (clutter_event_is_pointer_emulated (event))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  switch (event->scroll.scroll_source)
 | 
			
		||||
    {
 | 
			
		||||
    case CLUTTER_SCROLL_SOURCE_WHEEL:
 | 
			
		||||
      source = WL_POINTER_AXIS_SOURCE_WHEEL;
 | 
			
		||||
      break;
 | 
			
		||||
    case CLUTTER_SCROLL_SOURCE_FINGER:
 | 
			
		||||
      source = WL_POINTER_AXIS_SOURCE_FINGER;
 | 
			
		||||
      break;
 | 
			
		||||
    case CLUTTER_SCROLL_SOURCE_CONTINUOUS:
 | 
			
		||||
      source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      source = WL_POINTER_AXIS_SOURCE_WHEEL;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  switch (clutter_event_get_scroll_direction (event))
 | 
			
		||||
    {
 | 
			
		||||
    case CLUTTER_SCROLL_UP:
 | 
			
		||||
      y_value = -DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      y_discrete = -1;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_DOWN:
 | 
			
		||||
      y_value = DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      y_discrete = 1;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_LEFT:
 | 
			
		||||
      x_value = -DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      x_discrete = -1;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_RIGHT:
 | 
			
		||||
      x_value = DEFAULT_AXIS_STEP_DISTANCE;
 | 
			
		||||
      x_discrete = 1;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case CLUTTER_SCROLL_SMOOTH:
 | 
			
		||||
@@ -537,13 +662,44 @@ handle_scroll_event (MetaWaylandPointer *pointer,
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
 | 
			
		||||
        {
 | 
			
		||||
          if (wl_resource_get_version (resource) >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION)
 | 
			
		||||
            wl_pointer_send_axis_source (resource, source);
 | 
			
		||||
 | 
			
		||||
          /* X axis */
 | 
			
		||||
          if (x_discrete != 0 &&
 | 
			
		||||
              wl_resource_get_version (resource) >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
 | 
			
		||||
            wl_pointer_send_axis_discrete (resource,
 | 
			
		||||
                                           WL_POINTER_AXIS_HORIZONTAL_SCROLL,
 | 
			
		||||
                                           x_discrete);
 | 
			
		||||
 | 
			
		||||
          if (x_value)
 | 
			
		||||
            wl_pointer_send_axis (resource, clutter_event_get_time (event),
 | 
			
		||||
                                  WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
 | 
			
		||||
 | 
			
		||||
          if ((event->scroll.finish_flags & CLUTTER_SCROLL_FINISHED_HORIZONTAL) &&
 | 
			
		||||
              wl_resource_get_version (resource) >= WL_POINTER_AXIS_STOP_SINCE_VERSION)
 | 
			
		||||
            wl_pointer_send_axis_stop (resource,
 | 
			
		||||
                                       clutter_event_get_time (event),
 | 
			
		||||
                                       WL_POINTER_AXIS_HORIZONTAL_SCROLL);
 | 
			
		||||
          /* Y axis */
 | 
			
		||||
          if (y_discrete != 0 &&
 | 
			
		||||
              wl_resource_get_version (resource) >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
 | 
			
		||||
            wl_pointer_send_axis_discrete (resource,
 | 
			
		||||
                                           WL_POINTER_AXIS_VERTICAL_SCROLL,
 | 
			
		||||
                                           y_discrete);
 | 
			
		||||
 | 
			
		||||
          if (y_value)
 | 
			
		||||
            wl_pointer_send_axis (resource, clutter_event_get_time (event),
 | 
			
		||||
                                  WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
 | 
			
		||||
 | 
			
		||||
          if ((event->scroll.finish_flags & CLUTTER_SCROLL_FINISHED_VERTICAL) &&
 | 
			
		||||
              wl_resource_get_version (resource) >= WL_POINTER_AXIS_STOP_SINCE_VERSION)
 | 
			
		||||
            wl_pointer_send_axis_stop (resource,
 | 
			
		||||
                                       clutter_event_get_time (event),
 | 
			
		||||
                                       WL_POINTER_AXIS_VERTICAL_SCROLL);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      meta_wayland_pointer_broadcast_frame (pointer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -582,13 +738,57 @@ meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
broadcast_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
                 struct wl_resource *resource)
 | 
			
		||||
meta_wayland_pointer_send_enter (MetaWaylandPointer *pointer,
 | 
			
		||||
                                 struct wl_resource *pointer_resource,
 | 
			
		||||
                                 uint32_t            serial,
 | 
			
		||||
                                 MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  wl_fixed_t sx, sy;
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_get_relative_coordinates (pointer, pointer->focus_surface, &sx, &sy);
 | 
			
		||||
  wl_pointer_send_enter (resource, pointer->focus_serial, pointer->focus_surface->resource, sx, sy);
 | 
			
		||||
  meta_wayland_pointer_get_relative_coordinates (pointer, surface, &sx, &sy);
 | 
			
		||||
  wl_pointer_send_enter (pointer_resource,
 | 
			
		||||
                         serial,
 | 
			
		||||
                         surface->resource,
 | 
			
		||||
                         sx, sy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_send_leave (MetaWaylandPointer *pointer,
 | 
			
		||||
                                 struct wl_resource *pointer_resource,
 | 
			
		||||
                                 uint32_t            serial,
 | 
			
		||||
                                 MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  wl_pointer_send_leave (pointer_resource, serial, surface->resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_broadcast_enter (MetaWaylandPointer *pointer,
 | 
			
		||||
                                      uint32_t            serial,
 | 
			
		||||
                                      MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *pointer_resource;
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (pointer_resource,
 | 
			
		||||
                        &pointer->focus_client->pointer_resources)
 | 
			
		||||
    meta_wayland_pointer_send_enter (pointer, pointer_resource,
 | 
			
		||||
                                     serial, surface);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_broadcast_frame (pointer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pointer_broadcast_leave (MetaWaylandPointer *pointer,
 | 
			
		||||
                                      uint32_t            serial,
 | 
			
		||||
                                      MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  struct wl_resource *pointer_resource;
 | 
			
		||||
 | 
			
		||||
  wl_resource_for_each (pointer_resource,
 | 
			
		||||
                        &pointer->focus_client->pointer_resources)
 | 
			
		||||
    meta_wayland_pointer_send_leave (pointer, pointer_resource,
 | 
			
		||||
                                     serial, surface);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_broadcast_frame (pointer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -607,18 +807,14 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
        wl_resource_get_client (pointer->focus_surface->resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      uint32_t serial;
 | 
			
		||||
      struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
      serial = wl_display_next_serial (display);
 | 
			
		||||
 | 
			
		||||
      if (pointer->focus_client)
 | 
			
		||||
        {
 | 
			
		||||
          wl_resource_for_each (resource,
 | 
			
		||||
                                &pointer->focus_client->pointer_resources)
 | 
			
		||||
            {
 | 
			
		||||
              wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          meta_wayland_pointer_broadcast_leave (pointer,
 | 
			
		||||
                                                serial,
 | 
			
		||||
                                                pointer->focus_surface);
 | 
			
		||||
          pointer->focus_client = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -630,7 +826,6 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
    {
 | 
			
		||||
      struct wl_client *client = wl_resource_get_client (surface->resource);
 | 
			
		||||
      struct wl_display *display = wl_client_get_display (client);
 | 
			
		||||
      struct wl_resource *resource;
 | 
			
		||||
      ClutterPoint pos;
 | 
			
		||||
 | 
			
		||||
      pointer->focus_surface = surface;
 | 
			
		||||
@@ -649,12 +844,9 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
 | 
			
		||||
      if (pointer->focus_client)
 | 
			
		||||
        {
 | 
			
		||||
          pointer->focus_serial = wl_display_next_serial (display);
 | 
			
		||||
 | 
			
		||||
          wl_resource_for_each (resource,
 | 
			
		||||
                                &pointer->focus_client->pointer_resources)
 | 
			
		||||
            {
 | 
			
		||||
              broadcast_focus (pointer, resource);
 | 
			
		||||
            }
 | 
			
		||||
          meta_wayland_pointer_broadcast_enter (pointer,
 | 
			
		||||
                                                pointer->focus_serial,
 | 
			
		||||
                                                pointer->focus_surface);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -735,11 +927,10 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
 | 
			
		||||
  ClutterPoint pos;
 | 
			
		||||
 | 
			
		||||
  clutter_input_device_get_coords (pointer->device, NULL, &pos);
 | 
			
		||||
  clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
 | 
			
		||||
                                       pos.x, pos.y, &xf, &yf);
 | 
			
		||||
  meta_wayland_surface_get_relative_coordinates (surface, pos.x, pos.y, &xf, &yf);
 | 
			
		||||
 | 
			
		||||
  *sx = wl_fixed_from_double (xf) / surface->scale;
 | 
			
		||||
  *sy = wl_fixed_from_double (yf) / surface->scale;
 | 
			
		||||
  *sx = wl_fixed_from_double (xf);
 | 
			
		||||
  *sy = wl_fixed_from_double (yf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -930,7 +1121,12 @@ meta_wayland_pointer_create_new_resource (MetaWaylandPointer *pointer,
 | 
			
		||||
                  wl_resource_get_link (cr));
 | 
			
		||||
 | 
			
		||||
  if (pointer->focus_client == pointer_client)
 | 
			
		||||
    broadcast_focus (pointer, cr);
 | 
			
		||||
    {
 | 
			
		||||
      meta_wayland_pointer_send_enter (pointer, cr,
 | 
			
		||||
                                       pointer->focus_serial,
 | 
			
		||||
                                       pointer->focus_surface);
 | 
			
		||||
      meta_wayland_pointer_send_frame (pointer, cr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
@@ -961,6 +1157,108 @@ meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer)
 | 
			
		||||
  return meta_wayland_popup_grab_get_top_popup(grab);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
relative_pointer_destroy (struct wl_client *client,
 | 
			
		||||
                          struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_relative_pointer_v1_interface relative_pointer_interface = {
 | 
			
		||||
  relative_pointer_destroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
relative_pointer_manager_destroy (struct wl_client *client,
 | 
			
		||||
                                  struct wl_resource *resource)
 | 
			
		||||
{
 | 
			
		||||
  wl_resource_destroy (resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
relative_pointer_manager_get_relative_pointer (struct wl_client   *client,
 | 
			
		||||
                                               struct wl_resource *resource,
 | 
			
		||||
                                               uint32_t            id,
 | 
			
		||||
                                               struct wl_resource *pointer_resource)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource);
 | 
			
		||||
  struct wl_resource *cr;
 | 
			
		||||
  MetaWaylandPointerClient *pointer_client;
 | 
			
		||||
 | 
			
		||||
  cr = wl_resource_create (client, &zwp_relative_pointer_v1_interface,
 | 
			
		||||
                           wl_resource_get_version (resource), id);
 | 
			
		||||
  if (cr == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      wl_client_post_no_memory (client);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  wl_resource_set_implementation (cr, &relative_pointer_interface,
 | 
			
		||||
                                  pointer,
 | 
			
		||||
                                  meta_wayland_pointer_unbind_pointer_client_resource);
 | 
			
		||||
 | 
			
		||||
  pointer_client = meta_wayland_pointer_ensure_pointer_client (pointer, client);
 | 
			
		||||
 | 
			
		||||
  wl_list_insert (&pointer_client->relative_pointer_resources,
 | 
			
		||||
                  wl_resource_get_link (cr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager = {
 | 
			
		||||
  relative_pointer_manager_destroy,
 | 
			
		||||
  relative_pointer_manager_get_relative_pointer,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bind_relative_pointer_manager (struct wl_client *client,
 | 
			
		||||
                               void             *data,
 | 
			
		||||
                               uint32_t          version,
 | 
			
		||||
                               uint32_t          id)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = data;
 | 
			
		||||
  struct wl_resource *resource;
 | 
			
		||||
 | 
			
		||||
  resource = wl_resource_create (client,
 | 
			
		||||
                                 &zwp_relative_pointer_manager_v1_interface,
 | 
			
		||||
                                 1, id);
 | 
			
		||||
 | 
			
		||||
  if (version != 1)
 | 
			
		||||
    wl_resource_post_error (resource,
 | 
			
		||||
                            WL_DISPLAY_ERROR_INVALID_OBJECT,
 | 
			
		||||
                            "bound invalid version %u of "
 | 
			
		||||
                            "wp_relative_pointer_manager",
 | 
			
		||||
                            version);
 | 
			
		||||
 | 
			
		||||
  wl_resource_set_implementation (resource, &relative_pointer_manager,
 | 
			
		||||
                                  compositor,
 | 
			
		||||
                                  NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor)
 | 
			
		||||
{
 | 
			
		||||
  /* Relative pointer events are currently only supported by the native backend
 | 
			
		||||
   * so lets just advertise the extension when the native backend is used.
 | 
			
		||||
   */
 | 
			
		||||
#ifdef HAVE_NATIVE_BACKEND
 | 
			
		||||
  if (!META_IS_BACKEND_NATIVE (meta_get_backend ()))
 | 
			
		||||
    return;
 | 
			
		||||
#else
 | 
			
		||||
  return;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (!wl_global_create (compositor->wayland_display,
 | 
			
		||||
                         &zwp_relative_pointer_manager_v1_interface, 1,
 | 
			
		||||
                         compositor, bind_relative_pointer_manager))
 | 
			
		||||
    g_error ("Could not create relative pointer manager global");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandSeat *
 | 
			
		||||
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
 | 
			
		||||
  return seat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
#include "meta-wayland-pointer-gesture-swipe.h"
 | 
			
		||||
#include "meta-wayland-pointer-gesture-pinch.h"
 | 
			
		||||
#include "meta-wayland-surface.h"
 | 
			
		||||
#include "meta-wayland-pointer-constraints.h"
 | 
			
		||||
 | 
			
		||||
#include <meta/meta-cursor-tracker.h>
 | 
			
		||||
 | 
			
		||||
@@ -58,6 +59,7 @@ struct _MetaWaylandPointerClient
 | 
			
		||||
  struct wl_list pointer_resources;
 | 
			
		||||
  struct wl_list swipe_gesture_resources;
 | 
			
		||||
  struct wl_list pinch_gesture_resources;
 | 
			
		||||
  struct wl_list relative_pointer_resources;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandPointer
 | 
			
		||||
@@ -101,6 +103,9 @@ gboolean meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
 | 
			
		||||
void meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
 | 
			
		||||
                                       const ClutterEvent *event);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_send_relative_motion (MetaWaylandPointer *pointer,
 | 
			
		||||
                                                const ClutterEvent *event);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
 | 
			
		||||
                                       const ClutterEvent *event);
 | 
			
		||||
 | 
			
		||||
@@ -142,4 +147,8 @@ MetaWaylandPointerClient * meta_wayland_pointer_get_pointer_client (MetaWaylandP
 | 
			
		||||
                                                                    struct wl_client   *client);
 | 
			
		||||
void meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resource);
 | 
			
		||||
 | 
			
		||||
void meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor);
 | 
			
		||||
 | 
			
		||||
MetaWaylandSeat *meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer);
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_POINTER_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -405,3 +405,12 @@ meta_wayland_seat_get_grab_info (MetaWaylandSeat    *seat,
 | 
			
		||||
 | 
			
		||||
  return sequence || can_grab_surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_seat_can_popup (MetaWaylandSeat *seat,
 | 
			
		||||
                             uint32_t         serial)
 | 
			
		||||
{
 | 
			
		||||
  return (meta_wayland_pointer_can_popup (&seat->pointer, serial) ||
 | 
			
		||||
          meta_wayland_keyboard_can_popup (&seat->keyboard, serial) ||
 | 
			
		||||
          meta_wayland_touch_can_popup (&seat->touch, serial));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,5 +64,7 @@ gboolean meta_wayland_seat_get_grab_info (MetaWaylandSeat    *seat,
 | 
			
		||||
					  uint32_t            serial,
 | 
			
		||||
					  gfloat             *x,
 | 
			
		||||
					  gfloat             *y);
 | 
			
		||||
gboolean meta_wayland_seat_can_popup     (MetaWaylandSeat *seat,
 | 
			
		||||
                                          uint32_t         serial);
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_SEAT_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include "gtk-shell-server-protocol.h"
 | 
			
		||||
#include "xdg-shell-server-protocol.h"
 | 
			
		||||
#include "xdg-shell-unstable-v5-server-protocol.h"
 | 
			
		||||
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-xwayland-private.h"
 | 
			
		||||
@@ -55,6 +55,14 @@
 | 
			
		||||
#include "meta-surface-actor-wayland.h"
 | 
			
		||||
#include "meta-xwayland-private.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
  PENDING_STATE_SIGNAL_APPLIED,
 | 
			
		||||
 | 
			
		||||
  PENDING_STATE_SIGNAL_LAST_SIGNAL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static guint pending_state_signals[PENDING_STATE_SIGNAL_LAST_SIGNAL];
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandSurfaceRolePrivate
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface;
 | 
			
		||||
@@ -79,6 +87,10 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole,
 | 
			
		||||
                            meta_wayland_surface_role,
 | 
			
		||||
                            G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (MetaWaylandPendingState,
 | 
			
		||||
               meta_wayland_pending_state,
 | 
			
		||||
               G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandSurfaceRoleSubsurface
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurfaceRole parent;
 | 
			
		||||
@@ -257,8 +269,6 @@ dnd_surface_commit (MetaWaylandSurfaceRole  *surface_role,
 | 
			
		||||
    meta_wayland_surface_role_get_surface (surface_role);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_data_device_update_dnd_surface (&surface->compositor->seat->data_device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -470,7 +480,18 @@ move_pending_state (MetaWaylandPendingState *from,
 | 
			
		||||
  if (from->buffer)
 | 
			
		||||
    wl_list_remove (&from->buffer_destroy_listener.link);
 | 
			
		||||
 | 
			
		||||
  *to = *from;
 | 
			
		||||
  to->newly_attached = from->newly_attached;
 | 
			
		||||
  to->buffer = from->buffer;
 | 
			
		||||
  to->dx = from->dx;
 | 
			
		||||
  to->dy = from->dy;
 | 
			
		||||
  to->scale = from->scale;
 | 
			
		||||
  to->damage = from->damage;
 | 
			
		||||
  to->input_region = from->input_region;
 | 
			
		||||
  to->input_region_set = from->input_region_set;
 | 
			
		||||
  to->opaque_region = from->opaque_region;
 | 
			
		||||
  to->opaque_region_set = from->opaque_region_set;
 | 
			
		||||
  to->new_geometry = from->new_geometry;
 | 
			
		||||
  to->has_new_geometry = from->has_new_geometry;
 | 
			
		||||
 | 
			
		||||
  wl_list_init (&to->frame_callback_list);
 | 
			
		||||
  wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
 | 
			
		||||
@@ -481,6 +502,38 @@ move_pending_state (MetaWaylandPendingState *from,
 | 
			
		||||
  pending_state_init (from);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pending_state_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandPendingState *state = META_WAYLAND_PENDING_STATE (object);
 | 
			
		||||
 | 
			
		||||
  pending_state_destroy (state);
 | 
			
		||||
 | 
			
		||||
  G_OBJECT_CLASS (meta_wayland_pending_state_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pending_state_init (MetaWaylandPendingState *state)
 | 
			
		||||
{
 | 
			
		||||
  pending_state_init (state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_pending_state_class_init (MetaWaylandPendingStateClass *klass)
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
 | 
			
		||||
  object_class->finalize = meta_wayland_pending_state_finalize;
 | 
			
		||||
 | 
			
		||||
  pending_state_signals[PENDING_STATE_SIGNAL_APPLIED] =
 | 
			
		||||
    g_signal_new ("applied",
 | 
			
		||||
                  G_TYPE_FROM_CLASS (object_class),
 | 
			
		||||
                  G_SIGNAL_RUN_LAST,
 | 
			
		||||
                  0,
 | 
			
		||||
                  NULL, NULL, NULL,
 | 
			
		||||
                  G_TYPE_NONE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
subsurface_surface_commit (MetaWaylandSurfaceRole  *surface_role,
 | 
			
		||||
                           MetaWaylandPendingState *pending)
 | 
			
		||||
@@ -579,7 +632,7 @@ parent_surface_state_applied (gpointer data, gpointer user_data)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (is_surface_effectively_synchronized (surface))
 | 
			
		||||
    apply_pending_state (surface, &surface->sub.pending);
 | 
			
		||||
    apply_pending_state (surface, surface->sub.pending);
 | 
			
		||||
 | 
			
		||||
  meta_surface_actor_wayland_sync_subsurface_state (
 | 
			
		||||
    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
 | 
			
		||||
@@ -598,6 +651,7 @@ apply_pending_state (MetaWaylandSurface      *surface,
 | 
			
		||||
 | 
			
		||||
      if (pending->buffer)
 | 
			
		||||
        {
 | 
			
		||||
          meta_wayland_buffer_take_control (pending->buffer);
 | 
			
		||||
          CoglTexture *texture = meta_wayland_buffer_ensure_texture (pending->buffer);
 | 
			
		||||
          meta_surface_actor_wayland_set_texture (META_SURFACE_ACTOR_WAYLAND (surface->surface_actor), texture);
 | 
			
		||||
        }
 | 
			
		||||
@@ -609,6 +663,9 @@ apply_pending_state (MetaWaylandSurface      *surface,
 | 
			
		||||
  if (!cairo_region_is_empty (pending->damage))
 | 
			
		||||
    surface_process_damage (surface, pending->damage);
 | 
			
		||||
 | 
			
		||||
  if (pending->buffer && pending->buffer->copied_data)
 | 
			
		||||
    meta_wayland_buffer_release_control (pending->buffer);
 | 
			
		||||
 | 
			
		||||
  surface->offset_x += pending->dx;
 | 
			
		||||
  surface->offset_y += pending->dy;
 | 
			
		||||
 | 
			
		||||
@@ -648,6 +705,10 @@ apply_pending_state (MetaWaylandSurface      *surface,
 | 
			
		||||
      wl_list_init (&pending->frame_callback_list);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (pending,
 | 
			
		||||
                 pending_state_signals[PENDING_STATE_SIGNAL_APPLIED],
 | 
			
		||||
                 0);
 | 
			
		||||
 | 
			
		||||
  meta_surface_actor_wayland_sync_state (
 | 
			
		||||
    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor));
 | 
			
		||||
 | 
			
		||||
@@ -668,9 +729,9 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
 | 
			
		||||
   *     surface is in effective desynchronized mode.
 | 
			
		||||
   */
 | 
			
		||||
  if (is_surface_effectively_synchronized (surface))
 | 
			
		||||
    move_pending_state (&surface->pending, &surface->sub.pending);
 | 
			
		||||
    move_pending_state (surface->pending, surface->sub.pending);
 | 
			
		||||
  else
 | 
			
		||||
    apply_pending_state (surface, &surface->pending);
 | 
			
		||||
    apply_pending_state (surface, surface->pending);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -699,17 +760,17 @@ wl_surface_attach (struct wl_client *client,
 | 
			
		||||
  else
 | 
			
		||||
    buffer = NULL;
 | 
			
		||||
 | 
			
		||||
  if (surface->pending.buffer)
 | 
			
		||||
    wl_list_remove (&surface->pending.buffer_destroy_listener.link);
 | 
			
		||||
  if (surface->pending->buffer)
 | 
			
		||||
    wl_list_remove (&surface->pending->buffer_destroy_listener.link);
 | 
			
		||||
 | 
			
		||||
  surface->pending.newly_attached = TRUE;
 | 
			
		||||
  surface->pending.buffer = buffer;
 | 
			
		||||
  surface->pending.dx = dx;
 | 
			
		||||
  surface->pending.dy = dy;
 | 
			
		||||
  surface->pending->newly_attached = TRUE;
 | 
			
		||||
  surface->pending->buffer = buffer;
 | 
			
		||||
  surface->pending->dx = dx;
 | 
			
		||||
  surface->pending->dy = dy;
 | 
			
		||||
 | 
			
		||||
  if (buffer)
 | 
			
		||||
    wl_signal_add (&buffer->destroy_signal,
 | 
			
		||||
                   &surface->pending.buffer_destroy_listener);
 | 
			
		||||
                   &surface->pending->buffer_destroy_listener);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -727,7 +788,7 @@ wl_surface_damage (struct wl_client *client,
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  cairo_region_union_rectangle (surface->pending.damage, &rectangle);
 | 
			
		||||
  cairo_region_union_rectangle (surface->pending->damage, &rectangle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -757,7 +818,7 @@ wl_surface_frame (struct wl_client *client,
 | 
			
		||||
  callback->resource = wl_resource_create (client, &wl_callback_interface, META_WL_CALLBACK_VERSION, callback_id);
 | 
			
		||||
  wl_resource_set_implementation (callback->resource, NULL, callback, destroy_frame_callback);
 | 
			
		||||
 | 
			
		||||
  wl_list_insert (surface->pending.frame_callback_list.prev, &callback->link);
 | 
			
		||||
  wl_list_insert (surface->pending->frame_callback_list.prev, &callback->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -771,14 +832,14 @@ wl_surface_set_opaque_region (struct wl_client *client,
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&surface->pending.opaque_region, cairo_region_destroy);
 | 
			
		||||
  g_clear_pointer (&surface->pending->opaque_region, cairo_region_destroy);
 | 
			
		||||
  if (region_resource)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
 | 
			
		||||
      cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
 | 
			
		||||
      surface->pending.opaque_region = cairo_region_copy (cr_region);
 | 
			
		||||
      surface->pending->opaque_region = cairo_region_copy (cr_region);
 | 
			
		||||
    }
 | 
			
		||||
  surface->pending.opaque_region_set = TRUE;
 | 
			
		||||
  surface->pending->opaque_region_set = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -792,14 +853,14 @@ wl_surface_set_input_region (struct wl_client *client,
 | 
			
		||||
  if (!surface)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&surface->pending.input_region, cairo_region_destroy);
 | 
			
		||||
  g_clear_pointer (&surface->pending->input_region, cairo_region_destroy);
 | 
			
		||||
  if (region_resource)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
 | 
			
		||||
      cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
 | 
			
		||||
      surface->pending.input_region = cairo_region_copy (cr_region);
 | 
			
		||||
      surface->pending->input_region = cairo_region_copy (cr_region);
 | 
			
		||||
    }
 | 
			
		||||
  surface->pending.input_region_set = TRUE;
 | 
			
		||||
  surface->pending->input_region_set = TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -830,7 +891,7 @@ wl_surface_set_buffer_scale (struct wl_client *client,
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
 | 
			
		||||
  if (scale > 0)
 | 
			
		||||
    surface->pending.scale = scale;
 | 
			
		||||
    surface->pending->scale = scale;
 | 
			
		||||
  else
 | 
			
		||||
    g_warning ("Trying to set invalid buffer_scale of %d\n", scale);
 | 
			
		||||
}
 | 
			
		||||
@@ -933,22 +994,26 @@ set_surface_is_on_output (MetaWaylandSurface *surface,
 | 
			
		||||
                          MetaWaylandOutput *wayland_output,
 | 
			
		||||
                          gboolean is_on_output)
 | 
			
		||||
{
 | 
			
		||||
  gboolean was_on_output = g_hash_table_contains (surface->outputs,
 | 
			
		||||
                                                  wayland_output);
 | 
			
		||||
  gpointer orig_id;
 | 
			
		||||
  gboolean was_on_output = g_hash_table_lookup_extended (surface->outputs_to_destroy_notify_id,
 | 
			
		||||
                                                         wayland_output,
 | 
			
		||||
                                                         NULL, &orig_id);
 | 
			
		||||
 | 
			
		||||
  if (!was_on_output && is_on_output)
 | 
			
		||||
    {
 | 
			
		||||
      g_signal_connect (wayland_output, "output-destroyed",
 | 
			
		||||
                        G_CALLBACK (surface_handle_output_destroy),
 | 
			
		||||
                        surface);
 | 
			
		||||
      g_hash_table_add (surface->outputs, wayland_output);
 | 
			
		||||
      gulong id;
 | 
			
		||||
 | 
			
		||||
      id = g_signal_connect (wayland_output, "output-destroyed",
 | 
			
		||||
                             G_CALLBACK (surface_handle_output_destroy),
 | 
			
		||||
                             surface);
 | 
			
		||||
      g_hash_table_insert (surface->outputs_to_destroy_notify_id, wayland_output,
 | 
			
		||||
                           GSIZE_TO_POINTER ((gsize)id));
 | 
			
		||||
      surface_entered_output (surface, wayland_output);
 | 
			
		||||
    }
 | 
			
		||||
  else if (was_on_output && !is_on_output)
 | 
			
		||||
    {
 | 
			
		||||
      g_hash_table_remove (surface->outputs, wayland_output);
 | 
			
		||||
      g_signal_handlers_disconnect_by_func  (
 | 
			
		||||
        wayland_output, (gpointer)surface_handle_output_destroy, surface);
 | 
			
		||||
      g_hash_table_remove (surface->outputs_to_destroy_notify_id, wayland_output);
 | 
			
		||||
      g_signal_handler_disconnect (wayland_output, (gulong) GPOINTER_TO_SIZE (orig_id));
 | 
			
		||||
      surface_left_output (surface, wayland_output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -986,6 +1051,12 @@ update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
 | 
			
		||||
  set_surface_is_on_output (surface, wayland_output, is_on_output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
surface_output_disconnect_signal (gpointer key, gpointer value, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
  g_signal_handler_disconnect (key, (gulong) GPOINTER_TO_SIZE (value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
@@ -1021,8 +1092,11 @@ wl_surface_destructor (struct wl_resource *resource)
 | 
			
		||||
  if (surface->window)
 | 
			
		||||
    destroy_window (surface);
 | 
			
		||||
 | 
			
		||||
  g_list_free_full (surface->pointer_constraints,
 | 
			
		||||
                    (GDestroyNotify) meta_wayland_pointer_constraint_destroy);
 | 
			
		||||
 | 
			
		||||
  surface_set_buffer (surface, NULL);
 | 
			
		||||
  pending_state_destroy (&surface->pending);
 | 
			
		||||
  g_clear_object (&surface->pending);
 | 
			
		||||
 | 
			
		||||
  if (surface->opaque_region)
 | 
			
		||||
    cairo_region_destroy (surface->opaque_region);
 | 
			
		||||
@@ -1036,7 +1110,8 @@ wl_surface_destructor (struct wl_resource *resource)
 | 
			
		||||
 | 
			
		||||
  meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
 | 
			
		||||
 | 
			
		||||
  g_hash_table_unref (surface->outputs);
 | 
			
		||||
  g_hash_table_foreach (surface->outputs_to_destroy_notify_id, surface_output_disconnect_signal, surface);
 | 
			
		||||
  g_hash_table_unref (surface->outputs_to_destroy_notify_id);
 | 
			
		||||
 | 
			
		||||
  wl_list_for_each_safe (cb, next, &surface->pending_frame_callback_list, link)
 | 
			
		||||
    wl_resource_destroy (cb->resource);
 | 
			
		||||
@@ -1060,6 +1135,13 @@ wl_surface_destructor (struct wl_resource *resource)
 | 
			
		||||
  meta_wayland_compositor_repick (compositor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
surface_actor_painting (MetaSurfaceActorWayland *surface_actor,
 | 
			
		||||
                        MetaWaylandSurface      *surface)
 | 
			
		||||
{
 | 
			
		||||
  meta_wayland_surface_update_outputs (surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandSurface *
 | 
			
		||||
meta_wayland_surface_create (MetaWaylandCompositor *compositor,
 | 
			
		||||
                             struct wl_client      *client,
 | 
			
		||||
@@ -1079,11 +1161,16 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
 | 
			
		||||
 | 
			
		||||
  wl_list_init (&surface->pending_frame_callback_list);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect_object (surface->surface_actor,
 | 
			
		||||
                           "painting",
 | 
			
		||||
                           G_CALLBACK (surface_actor_painting),
 | 
			
		||||
                           surface,
 | 
			
		||||
                           0);
 | 
			
		||||
 | 
			
		||||
  sync_drag_dest_funcs (surface);
 | 
			
		||||
 | 
			
		||||
  surface->outputs = g_hash_table_new (NULL, NULL);
 | 
			
		||||
  surface->outputs_to_destroy_notify_id = g_hash_table_new (NULL, NULL);
 | 
			
		||||
 | 
			
		||||
  pending_state_init (&surface->pending);
 | 
			
		||||
  return surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1286,11 +1373,11 @@ xdg_surface_set_window_geometry (struct wl_client *client,
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
 | 
			
		||||
 | 
			
		||||
  surface->pending.has_new_geometry = TRUE;
 | 
			
		||||
  surface->pending.new_geometry.x = x;
 | 
			
		||||
  surface->pending.new_geometry.y = y;
 | 
			
		||||
  surface->pending.new_geometry.width = width;
 | 
			
		||||
  surface->pending.new_geometry.height = height;
 | 
			
		||||
  surface->pending->has_new_geometry = TRUE;
 | 
			
		||||
  surface->pending->new_geometry.x = x;
 | 
			
		||||
  surface->pending->new_geometry.y = y;
 | 
			
		||||
  surface->pending->new_geometry.width = width;
 | 
			
		||||
  surface->pending->new_geometry.height = height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -1422,8 +1509,8 @@ handle_popup_parent_destroyed (struct wl_listener *listener, void *data)
 | 
			
		||||
  MetaWaylandSurface *surface =
 | 
			
		||||
    wl_container_of (listener, surface, popup.parent_destroy_listener);
 | 
			
		||||
 | 
			
		||||
  wl_resource_post_error (surface->xdg_popup,
 | 
			
		||||
                          XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,
 | 
			
		||||
  wl_resource_post_error (surface->xdg_shell_resource,
 | 
			
		||||
                          XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
 | 
			
		||||
                          "destroyed popup not top most popup");
 | 
			
		||||
  surface->popup.parent = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -1441,8 +1528,8 @@ handle_popup_destroyed (struct wl_listener *listener, void *data)
 | 
			
		||||
  top_popup = meta_wayland_popup_get_top_popup (popup);
 | 
			
		||||
  if (surface != top_popup)
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (surface->xdg_popup,
 | 
			
		||||
                              XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,
 | 
			
		||||
      wl_resource_post_error (surface->xdg_shell_resource,
 | 
			
		||||
                              XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
 | 
			
		||||
                              "destroyed popup not top most popup");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1493,7 +1580,7 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
 | 
			
		||||
      (parent_surf->xdg_popup == NULL && parent_surf->xdg_surface == NULL))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (resource,
 | 
			
		||||
                              XDG_POPUP_ERROR_INVALID_PARENT,
 | 
			
		||||
                              XDG_SHELL_ERROR_INVALID_POPUP_PARENT,
 | 
			
		||||
                              "invalid parent surface");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1503,7 +1590,7 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
 | 
			
		||||
      (top_popup != NULL && parent_surf != top_popup))
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (resource,
 | 
			
		||||
                              XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP,
 | 
			
		||||
                              XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP,
 | 
			
		||||
                              "parent not top most surface");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1515,15 +1602,15 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
 | 
			
		||||
                                  surface,
 | 
			
		||||
                                  xdg_popup_destructor);
 | 
			
		||||
 | 
			
		||||
  if (!meta_wayland_pointer_can_popup (&seat->pointer, serial))
 | 
			
		||||
  surface->xdg_popup = popup_resource;
 | 
			
		||||
  surface->xdg_shell_resource = resource;
 | 
			
		||||
 | 
			
		||||
  if (!meta_wayland_seat_can_popup (seat, serial))
 | 
			
		||||
    {
 | 
			
		||||
      xdg_popup_send_popup_done (popup_resource);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  surface->xdg_popup = popup_resource;
 | 
			
		||||
  surface->xdg_shell_resource = resource;
 | 
			
		||||
 | 
			
		||||
  surface->popup.parent = parent_surf;
 | 
			
		||||
  surface->popup.parent_destroy_listener.notify = handle_popup_parent_destroyed;
 | 
			
		||||
  wl_resource_add_destroy_listener (parent_surf->resource,
 | 
			
		||||
@@ -1739,7 +1826,7 @@ wl_shell_surface_set_popup (struct wl_client *client,
 | 
			
		||||
 | 
			
		||||
  wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL);
 | 
			
		||||
 | 
			
		||||
  if (!meta_wayland_pointer_can_popup (&seat->pointer, serial))
 | 
			
		||||
  if (!meta_wayland_seat_can_popup (seat, serial))
 | 
			
		||||
    {
 | 
			
		||||
      wl_shell_surface_send_popup_done (resource);
 | 
			
		||||
      return;
 | 
			
		||||
@@ -1942,8 +2029,21 @@ get_gtk_surface (struct wl_client *client,
 | 
			
		||||
  wl_resource_set_implementation (surface->gtk_surface, &meta_wayland_gtk_surface_interface, surface, gtk_surface_destructor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_startup_id (struct wl_client   *client,
 | 
			
		||||
                struct wl_resource *resource,
 | 
			
		||||
                const char         *startup_id)
 | 
			
		||||
{
 | 
			
		||||
  MetaDisplay *display;
 | 
			
		||||
 | 
			
		||||
  display = meta_get_display ();
 | 
			
		||||
  meta_startup_notification_remove_sequence (display->startup_notification,
 | 
			
		||||
                                             startup_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct gtk_shell_interface meta_wayland_gtk_shell_interface = {
 | 
			
		||||
  get_gtk_surface
 | 
			
		||||
  get_gtk_surface,
 | 
			
		||||
  set_startup_id
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -1957,7 +2057,7 @@ bind_gtk_shell (struct wl_client *client,
 | 
			
		||||
 | 
			
		||||
  resource = wl_resource_create (client, >k_shell_interface, version, id);
 | 
			
		||||
 | 
			
		||||
  if (version != META_GTK_SHELL_VERSION)
 | 
			
		||||
  if (version < 2)
 | 
			
		||||
    {
 | 
			
		||||
      wl_resource_post_error (resource,
 | 
			
		||||
                              WL_DISPLAY_ERROR_INVALID_OBJECT,
 | 
			
		||||
@@ -1999,7 +2099,7 @@ wl_subsurface_destructor (struct wl_resource *resource)
 | 
			
		||||
      surface->sub.parent = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  pending_state_destroy (&surface->sub.pending);
 | 
			
		||||
  g_clear_object (&surface->sub.pending);
 | 
			
		||||
  surface->wl_subsurface = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2125,7 +2225,7 @@ wl_subsurface_set_desync (struct wl_client *client,
 | 
			
		||||
  surface->sub.synchronous = FALSE;
 | 
			
		||||
  if (was_effectively_synchronized &&
 | 
			
		||||
      !is_surface_effectively_synchronized (surface))
 | 
			
		||||
    apply_pending_state (surface, &surface->sub.pending);
 | 
			
		||||
    apply_pending_state (surface, surface->sub.pending);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = {
 | 
			
		||||
@@ -2189,7 +2289,7 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
 | 
			
		||||
  surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version (resource), id);
 | 
			
		||||
  wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, wl_subsurface_destructor);
 | 
			
		||||
 | 
			
		||||
  pending_state_init (&surface->sub.pending);
 | 
			
		||||
  surface->sub.pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
 | 
			
		||||
  surface->sub.synchronous = TRUE;
 | 
			
		||||
  surface->sub.parent = parent;
 | 
			
		||||
  surface->sub.parent_destroy_listener.notify = surface_handle_parent_surface_destroyed;
 | 
			
		||||
@@ -2376,6 +2476,15 @@ meta_wayland_surface_drag_dest_drop (MetaWaylandSurface *surface)
 | 
			
		||||
  surface->dnd.funcs->drop (data_device, surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_surface_drag_dest_update (MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
 | 
			
		||||
 | 
			
		||||
  surface->dnd.funcs->update (data_device, surface);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWindow *
 | 
			
		||||
meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
@@ -2395,9 +2504,79 @@ meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_surface_add_pointer_constraint (MetaWaylandSurface           *surface,
 | 
			
		||||
                                             MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  surface->pointer_constraints = g_list_append (surface->pointer_constraints,
 | 
			
		||||
                                                constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_surface_remove_pointer_constraint (MetaWaylandSurface           *surface,
 | 
			
		||||
                                                MetaWaylandPointerConstraint *constraint)
 | 
			
		||||
{
 | 
			
		||||
  surface->pointer_constraints = g_list_remove (surface->pointer_constraints,
 | 
			
		||||
                                                constraint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaWaylandPointerConstraint *
 | 
			
		||||
meta_wayland_surface_get_pointer_constraint_for_seat (MetaWaylandSurface *surface,
 | 
			
		||||
                                                      MetaWaylandSeat    *seat)
 | 
			
		||||
{
 | 
			
		||||
  GList *iter;
 | 
			
		||||
 | 
			
		||||
  for (iter = surface->pointer_constraints; iter; iter = iter->next)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandPointerConstraint *constraint = iter->data;
 | 
			
		||||
 | 
			
		||||
      if (seat == meta_wayland_pointer_constraint_get_seat (constraint))
 | 
			
		||||
        return constraint;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
 | 
			
		||||
                                               float               abs_x,
 | 
			
		||||
                                               float               abs_y,
 | 
			
		||||
                                               float               *sx,
 | 
			
		||||
                                               float               *sy)
 | 
			
		||||
{
 | 
			
		||||
  ClutterActor *actor =
 | 
			
		||||
    CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor));
 | 
			
		||||
 | 
			
		||||
  clutter_actor_transform_stage_point (actor, abs_x, abs_y, sx, sy);
 | 
			
		||||
  *sx /= surface->scale;
 | 
			
		||||
  *sy /= surface->scale;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
 | 
			
		||||
                                               float               sx,
 | 
			
		||||
                                               float               sy,
 | 
			
		||||
                                               float               *x,
 | 
			
		||||
                                               float               *y)
 | 
			
		||||
{
 | 
			
		||||
  ClutterActor *actor =
 | 
			
		||||
    CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor));
 | 
			
		||||
  ClutterVertex sv = {
 | 
			
		||||
    .x = sx * surface->scale,
 | 
			
		||||
    .y = sy * surface->scale,
 | 
			
		||||
  };
 | 
			
		||||
  ClutterVertex v = { 0 };
 | 
			
		||||
 | 
			
		||||
  clutter_actor_apply_relative_transform_to_point (actor, NULL, &sv, &v);
 | 
			
		||||
 | 
			
		||||
  *x = v.x;
 | 
			
		||||
  *y = v.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_surface_init (MetaWaylandSurface *surface)
 | 
			
		||||
{
 | 
			
		||||
  surface->pending = g_object_new (META_TYPE_WAYLAND_PENDING_STATE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#include "meta-wayland-types.h"
 | 
			
		||||
#include "meta-surface-actor.h"
 | 
			
		||||
#include "backends/meta-monitor-manager-private.h"
 | 
			
		||||
#include "meta-wayland-pointer-constraints.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _MetaWaylandPendingState MetaWaylandPendingState;
 | 
			
		||||
 | 
			
		||||
@@ -44,6 +45,12 @@ G_DECLARE_FINAL_TYPE (MetaWaylandSurface,
 | 
			
		||||
G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRole, meta_wayland_surface_role,
 | 
			
		||||
                          META, WAYLAND_SURFACE_ROLE, GObject);
 | 
			
		||||
 | 
			
		||||
#define META_TYPE_WAYLAND_PENDING_STATE (meta_wayland_pending_state_get_type ())
 | 
			
		||||
G_DECLARE_FINAL_TYPE (MetaWaylandPendingState,
 | 
			
		||||
                      meta_wayland_pending_state,
 | 
			
		||||
                      META, WAYLAND_PENDING_STATE,
 | 
			
		||||
                      GObject);
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandSurfaceRoleClass
 | 
			
		||||
{
 | 
			
		||||
  GObjectClass parent_class;
 | 
			
		||||
@@ -92,6 +99,8 @@ G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleDND,
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandPendingState
 | 
			
		||||
{
 | 
			
		||||
  GObject parent;
 | 
			
		||||
 | 
			
		||||
  /* wl_surface.attach */
 | 
			
		||||
  gboolean newly_attached;
 | 
			
		||||
  MetaWaylandBuffer *buffer;
 | 
			
		||||
@@ -128,6 +137,8 @@ struct _MetaWaylandDragDestFuncs
 | 
			
		||||
                      const ClutterEvent    *event);
 | 
			
		||||
  void (* drop)      (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                      MetaWaylandSurface    *surface);
 | 
			
		||||
  void (* update)    (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                      MetaWaylandSurface    *surface);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _MetaWaylandSurface
 | 
			
		||||
@@ -147,7 +158,7 @@ struct _MetaWaylandSurface
 | 
			
		||||
  int scale;
 | 
			
		||||
  int32_t offset_x, offset_y;
 | 
			
		||||
  GList *subsurfaces;
 | 
			
		||||
  GHashTable *outputs;
 | 
			
		||||
  GHashTable *outputs_to_destroy_notify_id;
 | 
			
		||||
 | 
			
		||||
  /* List of pending frame callbacks that needs to stay queued longer than one
 | 
			
		||||
   * commit sequence, such as when it has not yet been assigned a role.
 | 
			
		||||
@@ -159,7 +170,7 @@ struct _MetaWaylandSurface
 | 
			
		||||
  } dnd;
 | 
			
		||||
 | 
			
		||||
  /* All the pending state that wl_surface.commit will apply. */
 | 
			
		||||
  MetaWaylandPendingState pending;
 | 
			
		||||
  MetaWaylandPendingState *pending;
 | 
			
		||||
 | 
			
		||||
  /* Extension resources. */
 | 
			
		||||
  struct wl_resource *xdg_surface;
 | 
			
		||||
@@ -200,13 +211,15 @@ struct _MetaWaylandSurface
 | 
			
		||||
     * state here.
 | 
			
		||||
     */
 | 
			
		||||
    gboolean synchronous;
 | 
			
		||||
    MetaWaylandPendingState pending;
 | 
			
		||||
    MetaWaylandPendingState *pending;
 | 
			
		||||
 | 
			
		||||
    int32_t pending_x;
 | 
			
		||||
    int32_t pending_y;
 | 
			
		||||
    gboolean pending_pos;
 | 
			
		||||
    GSList *pending_placement_ops;
 | 
			
		||||
  } sub;
 | 
			
		||||
 | 
			
		||||
  GList *pointer_constraints;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void                meta_wayland_shell_init     (MetaWaylandCompositor *compositor);
 | 
			
		||||
@@ -240,6 +253,7 @@ void                meta_wayland_surface_drag_dest_motion    (MetaWaylandSurface
 | 
			
		||||
                                                              const ClutterEvent   *event);
 | 
			
		||||
void                meta_wayland_surface_drag_dest_focus_out (MetaWaylandSurface   *surface);
 | 
			
		||||
void                meta_wayland_surface_drag_dest_drop      (MetaWaylandSurface   *surface);
 | 
			
		||||
void                meta_wayland_surface_drag_dest_update    (MetaWaylandSurface   *surface);
 | 
			
		||||
 | 
			
		||||
void                meta_wayland_surface_update_outputs (MetaWaylandSurface *surface);
 | 
			
		||||
 | 
			
		||||
@@ -250,6 +264,27 @@ void                meta_wayland_surface_queue_pending_frame_callbacks (MetaWayl
 | 
			
		||||
void                meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface      *surface,
 | 
			
		||||
                                                                              MetaWaylandPendingState *pending);
 | 
			
		||||
 | 
			
		||||
void                meta_wayland_surface_add_pointer_constraint (MetaWaylandSurface           *surface,
 | 
			
		||||
                                                                 MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
 | 
			
		||||
void                meta_wayland_surface_remove_pointer_constraint (MetaWaylandSurface           *surface,
 | 
			
		||||
                                                                    MetaWaylandPointerConstraint *constraint);
 | 
			
		||||
MetaWaylandPointerConstraint *
 | 
			
		||||
                    meta_wayland_surface_get_pointer_constraint_for_seat (MetaWaylandSurface *surface,
 | 
			
		||||
                                                                          MetaWaylandSeat    *seat);
 | 
			
		||||
 | 
			
		||||
void                meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface,
 | 
			
		||||
                                                                   float               abs_x,
 | 
			
		||||
                                                                   float               abs_y,
 | 
			
		||||
                                                                   float              *sx,
 | 
			
		||||
                                                                   float              *sy);
 | 
			
		||||
 | 
			
		||||
void                meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
 | 
			
		||||
                                                                   float               sx,
 | 
			
		||||
                                                                   float               sy,
 | 
			
		||||
                                                                   float              *x,
 | 
			
		||||
                                                                   float              *y);
 | 
			
		||||
 | 
			
		||||
MetaWaylandSurface * meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -208,8 +208,8 @@ touch_get_relative_coordinates (MetaWaylandTouch   *touch,
 | 
			
		||||
                                           &event_x, &event_y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  *x = event_x;
 | 
			
		||||
  *y = event_y;
 | 
			
		||||
  *x = event_x / surface->scale;
 | 
			
		||||
  *y = event_y / surface->scale;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -575,6 +575,26 @@ meta_wayland_touch_create_new_resource (MetaWaylandTouch   *touch,
 | 
			
		||||
  wl_list_insert (&touch->resource_list, wl_resource_get_link (cr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
meta_wayland_touch_can_popup (MetaWaylandTouch *touch,
 | 
			
		||||
                              uint32_t          serial)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandTouchInfo *touch_info;
 | 
			
		||||
  GHashTableIter iter;
 | 
			
		||||
 | 
			
		||||
  if (!touch->touches)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  g_hash_table_iter_init (&iter, touch->touches);
 | 
			
		||||
 | 
			
		||||
  while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &touch_info))
 | 
			
		||||
    {
 | 
			
		||||
      if (touch_info->slot_serial == serial)
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ClutterEventSequence *
 | 
			
		||||
meta_wayland_touch_find_grab_sequence (MetaWaylandTouch   *touch,
 | 
			
		||||
                                       MetaWaylandSurface *surface,
 | 
			
		||||
 
 | 
			
		||||
@@ -70,4 +70,7 @@ gboolean meta_wayland_touch_get_press_coords (MetaWaylandTouch     *touch,
 | 
			
		||||
                                              gfloat               *x,
 | 
			
		||||
                                              gfloat               *y);
 | 
			
		||||
 | 
			
		||||
gboolean meta_wayland_touch_can_popup        (MetaWaylandTouch *touch,
 | 
			
		||||
                                              uint32_t          serial);
 | 
			
		||||
 | 
			
		||||
#endif /* META_WAYLAND_TOUCH_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@ typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface;
 | 
			
		||||
typedef struct _MetaWaylandPopupGrab MetaWaylandPopupGrab;
 | 
			
		||||
typedef struct _MetaWaylandPopup MetaWaylandPopup;
 | 
			
		||||
typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard;
 | 
			
		||||
typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab;
 | 
			
		||||
typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface;
 | 
			
		||||
typedef struct _MetaWaylandTouch MetaWaylandTouch;
 | 
			
		||||
typedef struct _MetaWaylandDragDestFuncs MetaWaylandDragDestFuncs;
 | 
			
		||||
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,14 +36,14 @@
 | 
			
		||||
 | 
			
		||||
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
 | 
			
		||||
#define META_WL_COMPOSITOR_VERSION          3
 | 
			
		||||
#define META_WL_DATA_DEVICE_MANAGER_VERSION 2
 | 
			
		||||
#define META_WL_DATA_DEVICE_MANAGER_VERSION 3
 | 
			
		||||
#define META_XDG_SHELL_VERSION              1
 | 
			
		||||
#define META_WL_SHELL_VERSION               1
 | 
			
		||||
#define META_WL_SEAT_VERSION                4
 | 
			
		||||
#define META_WL_SEAT_VERSION                5
 | 
			
		||||
#define META_WL_OUTPUT_VERSION              2
 | 
			
		||||
#define META_XSERVER_VERSION                1
 | 
			
		||||
#define META_GTK_SHELL_VERSION              2
 | 
			
		||||
#define META_GTK_SHELL_VERSION              3
 | 
			
		||||
#define META_WL_SUBCOMPOSITOR_VERSION       1
 | 
			
		||||
#define META__WL_POINTER_GESTURES_VERSION   1
 | 
			
		||||
#define META_ZWP_POINTER_GESTURES_V1_VERSION    1
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -48,14 +48,6 @@ meta_wayland_compositor_get_default (void)
 | 
			
		||||
  return &_meta_wayland_compositor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static guint32
 | 
			
		||||
get_time (void)
 | 
			
		||||
{
 | 
			
		||||
  struct timeval tv;
 | 
			
		||||
  gettimeofday (&tv, NULL);
 | 
			
		||||
  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  GSource source;
 | 
			
		||||
@@ -186,7 +178,7 @@ meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor)
 | 
			
		||||
      MetaWaylandFrameCallback *callback =
 | 
			
		||||
        wl_container_of (compositor->frame_callbacks.next, callback, link);
 | 
			
		||||
 | 
			
		||||
      wl_callback_send_done (callback->resource, get_time ());
 | 
			
		||||
      wl_callback_send_done (callback->resource, g_get_monotonic_time () / 1000);
 | 
			
		||||
      wl_resource_destroy (callback->resource);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -336,14 +328,16 @@ meta_wayland_init (void)
 | 
			
		||||
  meta_wayland_shell_init (compositor);
 | 
			
		||||
  meta_wayland_pointer_gestures_init (compositor);
 | 
			
		||||
  meta_wayland_seat_init (compositor);
 | 
			
		||||
  meta_wayland_relative_pointer_init (compositor);
 | 
			
		||||
  meta_wayland_pointer_constraints_init (compositor);
 | 
			
		||||
 | 
			
		||||
  if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
 | 
			
		||||
    g_error ("Failed to start X Wayland");
 | 
			
		||||
 | 
			
		||||
  compositor->display_name = wl_display_add_socket_auto (compositor->wayland_display);
 | 
			
		||||
  if (compositor->display_name == NULL)
 | 
			
		||||
    g_error ("Failed to create socket");
 | 
			
		||||
 | 
			
		||||
  if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
 | 
			
		||||
    g_error ("Failed to start X Wayland");
 | 
			
		||||
 | 
			
		||||
  set_gnome_env ("DISPLAY", meta_wayland_get_xwayland_display_name (compositor));
 | 
			
		||||
  set_gnome_env ("WAYLAND_DISPLAY", meta_wayland_get_wayland_display_name (compositor));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@
 | 
			
		||||
#include "window-private.h"
 | 
			
		||||
#include "boxes-private.h"
 | 
			
		||||
#include "stack-tracker.h"
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#include "meta-wayland-surface.h"
 | 
			
		||||
#include "compositor/meta-surface-actor-wayland.h"
 | 
			
		||||
 | 
			
		||||
@@ -402,6 +403,11 @@ appears_focused_changed (GObject    *object,
 | 
			
		||||
                         gpointer    user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaWindow *window = META_WINDOW (object);
 | 
			
		||||
  MetaWaylandCompositor *wayland_compositor;
 | 
			
		||||
 | 
			
		||||
  wayland_compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  meta_wayland_pointer_constraint_maybe_remove_for_seat (wayland_compositor->seat,
 | 
			
		||||
                                                         window);
 | 
			
		||||
 | 
			
		||||
  /* When we're unmanaging, we remove focus from the window,
 | 
			
		||||
   * causing this to fire. Don't do anything in that case. */
 | 
			
		||||
@@ -409,6 +415,8 @@ appears_focused_changed (GObject    *object,
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  surface_state_changed (window);
 | 
			
		||||
 | 
			
		||||
  meta_wayland_pointer_constraint_maybe_enable_for_window (window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
@@ -108,6 +108,7 @@ enum {
 | 
			
		||||
  ATOM_DND_ACTION_MOVE,
 | 
			
		||||
  ATOM_DND_ACTION_COPY,
 | 
			
		||||
  ATOM_DND_ACTION_ASK,
 | 
			
		||||
  ATOM_DND_ACTION_PRIVATE,
 | 
			
		||||
  N_DND_ATOMS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -126,6 +127,7 @@ const gchar *atom_names[] = {
 | 
			
		||||
  "XdndActionMove",
 | 
			
		||||
  "XdndActionCopy",
 | 
			
		||||
  "XdndActionAsk",
 | 
			
		||||
  "XdndActionPrivate",
 | 
			
		||||
  NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -135,6 +137,33 @@ G_DEFINE_TYPE (MetaWaylandDataSourceXWayland, meta_wayland_data_source_xwayland,
 | 
			
		||||
               META_TYPE_WAYLAND_DATA_SOURCE);
 | 
			
		||||
 | 
			
		||||
/* XDND helpers */
 | 
			
		||||
static Atom
 | 
			
		||||
action_to_atom (uint32_t action)
 | 
			
		||||
{
 | 
			
		||||
  if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
 | 
			
		||||
    return xdnd_atoms[ATOM_DND_ACTION_COPY];
 | 
			
		||||
  else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
 | 
			
		||||
    return xdnd_atoms[ATOM_DND_ACTION_MOVE];
 | 
			
		||||
  else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
 | 
			
		||||
    return xdnd_atoms[ATOM_DND_ACTION_ASK];
 | 
			
		||||
  else
 | 
			
		||||
    return None;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum wl_data_device_manager_dnd_action
 | 
			
		||||
atom_to_action (Atom atom)
 | 
			
		||||
{
 | 
			
		||||
  if (atom == xdnd_atoms[ATOM_DND_ACTION_COPY] ||
 | 
			
		||||
      atom == xdnd_atoms[ATOM_DND_ACTION_PRIVATE])
 | 
			
		||||
    return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
 | 
			
		||||
  else if (atom == xdnd_atoms[ATOM_DND_ACTION_MOVE])
 | 
			
		||||
    return WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
 | 
			
		||||
  else if (atom == xdnd_atoms[ATOM_DND_ACTION_ASK])
 | 
			
		||||
    return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
 | 
			
		||||
  else
 | 
			
		||||
    return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
xdnd_send_enter (MetaXWaylandSelection *selection_data,
 | 
			
		||||
                 Window                 dest)
 | 
			
		||||
@@ -217,10 +246,21 @@ xdnd_send_position (MetaXWaylandSelection *selection_data,
 | 
			
		||||
                    int                    x,
 | 
			
		||||
                    int                    y)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  MetaSelectionBridge *selection = &selection_data->dnd.selection;
 | 
			
		||||
  MetaWaylandDataSource *source = compositor->seat->data_device.dnd_data_source;
 | 
			
		||||
  Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 | 
			
		||||
  uint32_t action = 0, user_action, actions;
 | 
			
		||||
  XEvent xev = { 0 };
 | 
			
		||||
 | 
			
		||||
  user_action = meta_wayland_data_source_get_user_action (source);
 | 
			
		||||
  actions = meta_wayland_data_source_get_actions (source);
 | 
			
		||||
 | 
			
		||||
  if (user_action & actions)
 | 
			
		||||
    action = user_action;
 | 
			
		||||
  if (!action)
 | 
			
		||||
    action = actions;
 | 
			
		||||
 | 
			
		||||
  xev.xclient.type = ClientMessage;
 | 
			
		||||
  xev.xclient.message_type = xdnd_atoms[ATOM_DND_POSITION];
 | 
			
		||||
  xev.xclient.format = 32;
 | 
			
		||||
@@ -230,7 +270,7 @@ xdnd_send_position (MetaXWaylandSelection *selection_data,
 | 
			
		||||
  xev.xclient.data.l[1] = 0;
 | 
			
		||||
  xev.xclient.data.l[2] = (x << 16) | y;
 | 
			
		||||
  xev.xclient.data.l[3] = time;
 | 
			
		||||
  xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
 | 
			
		||||
  xev.xclient.data.l[4] = action_to_atom (action);
 | 
			
		||||
 | 
			
		||||
  XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
 | 
			
		||||
}
 | 
			
		||||
@@ -262,6 +302,8 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
 | 
			
		||||
{
 | 
			
		||||
  MetaDndBridge *selection = &selection_data->dnd;
 | 
			
		||||
  Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 | 
			
		||||
  MetaWaylandDataSource *source = selection_data->dnd.selection.source;
 | 
			
		||||
  uint32_t action = 0;
 | 
			
		||||
  XEvent xev = { 0 };
 | 
			
		||||
 | 
			
		||||
  xev.xclient.type = ClientMessage;
 | 
			
		||||
@@ -273,8 +315,9 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
 | 
			
		||||
 | 
			
		||||
  if (accepted)
 | 
			
		||||
    {
 | 
			
		||||
      action = meta_wayland_data_source_get_current_action (source);
 | 
			
		||||
      xev.xclient.data.l[1] = 1; /* Drop successful */
 | 
			
		||||
      xev.xclient.data.l[2] = xdnd_atoms[ATOM_DND_ACTION_COPY];
 | 
			
		||||
      xev.xclient.data.l[2] = action_to_atom (action);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
 | 
			
		||||
@@ -283,7 +326,7 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
 | 
			
		||||
static void
 | 
			
		||||
xdnd_send_status (MetaXWaylandSelection *selection_data,
 | 
			
		||||
                  Window                 dest,
 | 
			
		||||
                  gboolean               accepted)
 | 
			
		||||
                  uint32_t               action)
 | 
			
		||||
{
 | 
			
		||||
  MetaDndBridge *selection = &selection_data->dnd;
 | 
			
		||||
  Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 | 
			
		||||
@@ -296,12 +339,10 @@ xdnd_send_status (MetaXWaylandSelection *selection_data,
 | 
			
		||||
 | 
			
		||||
  xev.xclient.data.l[0] = selection->dnd_window;
 | 
			
		||||
  xev.xclient.data.l[1] = 1 << 1; /* Bit 2: dest wants XdndPosition messages */
 | 
			
		||||
  xev.xclient.data.l[4] = action_to_atom (action);
 | 
			
		||||
 | 
			
		||||
  if (accepted)
 | 
			
		||||
    {
 | 
			
		||||
      xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
 | 
			
		||||
      xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
 | 
			
		||||
    }
 | 
			
		||||
  if (xev.xclient.data.l[4])
 | 
			
		||||
    xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
 | 
			
		||||
 | 
			
		||||
  XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
 | 
			
		||||
}
 | 
			
		||||
@@ -387,6 +428,32 @@ x11_selection_data_free (X11SelectionData *data)
 | 
			
		||||
  g_slice_free (X11SelectionData, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_selection_data_send_finished (MetaSelectionBridge *selection,
 | 
			
		||||
                                  gboolean             success)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t action = meta_wayland_data_source_get_current_action (selection->source);
 | 
			
		||||
 | 
			
		||||
  if (!selection->x11_selection)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (success && action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
 | 
			
		||||
    {
 | 
			
		||||
      Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 | 
			
		||||
 | 
			
		||||
      /* Request data deletion on the drag source */
 | 
			
		||||
      XConvertSelection (xdisplay,
 | 
			
		||||
                         selection->selection_atom,
 | 
			
		||||
                         gdk_x11_get_xatom_by_name ("DELETE"),
 | 
			
		||||
                         gdk_x11_get_xatom_by_name ("_META_SELECTION"),
 | 
			
		||||
                         selection->window,
 | 
			
		||||
                         CurrentTime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  xdnd_send_finished (selection->x11_selection->selection_data,
 | 
			
		||||
                      selection->owner, success);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_selection_data_finish (MetaSelectionBridge *selection,
 | 
			
		||||
                           gboolean             success)
 | 
			
		||||
@@ -395,13 +462,18 @@ x11_selection_data_finish (MetaSelectionBridge *selection,
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if (selection == &selection->x11_selection->selection_data->dnd.selection)
 | 
			
		||||
    xdnd_send_finished (selection->x11_selection->selection_data,
 | 
			
		||||
                        selection->owner, success);
 | 
			
		||||
    x11_selection_data_send_finished (selection, success);
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&selection->x11_selection,
 | 
			
		||||
                   (GDestroyNotify) x11_selection_data_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_selection_data_close (X11SelectionData *data)
 | 
			
		||||
{
 | 
			
		||||
  g_output_stream_close (data->stream, data->cancellable, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
x11_data_write_cb (GObject      *object,
 | 
			
		||||
                   GAsyncResult *res,
 | 
			
		||||
@@ -435,6 +507,7 @@ x11_data_write_cb (GObject      *object,
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      x11_selection_data_close (selection->x11_selection);
 | 
			
		||||
      x11_selection_data_finish (selection, success);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -693,6 +766,7 @@ meta_xwayland_selection_get_incr_chunk (MetaWaylandCompositor *compositor,
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Transfer has completed */
 | 
			
		||||
      x11_selection_data_close (selection->x11_selection);
 | 
			
		||||
      x11_selection_data_finish (selection, TRUE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -741,11 +815,15 @@ meta_x11_source_target (MetaWaylandDataSource *source,
 | 
			
		||||
  MetaWaylandDataSourceXWayland *source_xwayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
 | 
			
		||||
  MetaSelectionBridge *selection = source_xwayland->selection;
 | 
			
		||||
  uint32_t action = 0;
 | 
			
		||||
 | 
			
		||||
  if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
 | 
			
		||||
    {
 | 
			
		||||
      if (mime_type)
 | 
			
		||||
        action = meta_wayland_data_source_get_current_action (source);
 | 
			
		||||
 | 
			
		||||
      xdnd_send_status (compositor->xwayland_manager.selection_data,
 | 
			
		||||
                        selection->owner, mime_type != NULL);
 | 
			
		||||
                        selection->owner, action);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -756,10 +834,46 @@ meta_x11_source_cancel (MetaWaylandDataSource *source)
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
 | 
			
		||||
  MetaSelectionBridge *selection = source_xwayland->selection;
 | 
			
		||||
 | 
			
		||||
  x11_selection_data_send_finished (selection, FALSE);
 | 
			
		||||
  g_clear_pointer (&selection->x11_selection,
 | 
			
		||||
                   (GDestroyNotify) x11_selection_data_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_x11_source_action (MetaWaylandDataSource *source,
 | 
			
		||||
                        uint32_t               action)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  MetaWaylandDataSourceXWayland *source_xwayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
 | 
			
		||||
  MetaSelectionBridge *selection = source_xwayland->selection;
 | 
			
		||||
 | 
			
		||||
  if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
 | 
			
		||||
    {
 | 
			
		||||
      if (!meta_wayland_data_source_has_target (source))
 | 
			
		||||
        action = 0;
 | 
			
		||||
 | 
			
		||||
      xdnd_send_status (compositor->xwayland_manager.selection_data,
 | 
			
		||||
                        selection->owner, action);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_x11_source_drop_performed (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_x11_source_drag_finished (MetaWaylandDataSource *source)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandDataSourceXWayland *source_xwayland =
 | 
			
		||||
    META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
 | 
			
		||||
  MetaSelectionBridge *selection = source_xwayland->selection;
 | 
			
		||||
 | 
			
		||||
  if (selection->x11_selection)
 | 
			
		||||
    x11_selection_data_send_finished (selection, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_wayland_data_source_xwayland_init (MetaWaylandDataSourceXWayland *source_xwayland)
 | 
			
		||||
{
 | 
			
		||||
@@ -774,6 +888,9 @@ meta_wayland_data_source_xwayland_class_init (MetaWaylandDataSourceXWaylandClass
 | 
			
		||||
  data_source_class->send = meta_x11_source_send;
 | 
			
		||||
  data_source_class->target = meta_x11_source_target;
 | 
			
		||||
  data_source_class->cancel = meta_x11_source_cancel;
 | 
			
		||||
  data_source_class->action = meta_x11_source_action;
 | 
			
		||||
  data_source_class->drop_performed = meta_x11_source_drop_performed;
 | 
			
		||||
  data_source_class->drag_finished = meta_x11_source_drag_finished;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MetaWaylandDataSource *
 | 
			
		||||
@@ -837,11 +954,27 @@ meta_x11_drag_dest_drop (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                  meta_display_get_current_time_roundtrip (meta_get_display ()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_x11_drag_dest_update (MetaWaylandDataDevice *data_device,
 | 
			
		||||
                           MetaWaylandSurface    *surface)
 | 
			
		||||
{
 | 
			
		||||
  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
  MetaWaylandSeat *seat = compositor->seat;
 | 
			
		||||
  ClutterPoint pos;
 | 
			
		||||
 | 
			
		||||
  clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
 | 
			
		||||
  xdnd_send_position (compositor->xwayland_manager.selection_data,
 | 
			
		||||
                      compositor->xwayland_manager.selection_data->dnd.dnd_dest,
 | 
			
		||||
                      clutter_get_current_event_time (),
 | 
			
		||||
                      pos.x, pos.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const MetaWaylandDragDestFuncs meta_x11_drag_dest_funcs = {
 | 
			
		||||
  meta_x11_drag_dest_focus_in,
 | 
			
		||||
  meta_x11_drag_dest_focus_out,
 | 
			
		||||
  meta_x11_drag_dest_motion,
 | 
			
		||||
  meta_x11_drag_dest_drop
 | 
			
		||||
  meta_x11_drag_dest_drop,
 | 
			
		||||
  meta_x11_drag_dest_update
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const MetaWaylandDragDestFuncs *
 | 
			
		||||
@@ -1135,6 +1268,10 @@ meta_xwayland_selection_handle_selection_request (MetaWaylandCompositor *composi
 | 
			
		||||
                                              selection->timestamp);
 | 
			
		||||
      reply_selection_request (event, TRUE);
 | 
			
		||||
    }
 | 
			
		||||
  else if (data_source && event->target == gdk_x11_get_xatom_by_name ("DELETE"))
 | 
			
		||||
    {
 | 
			
		||||
      reply_selection_request (event, TRUE);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      if (data_source &&
 | 
			
		||||
@@ -1257,6 +1394,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
 | 
			
		||||
  if (event->window == dnd->selection.window)
 | 
			
		||||
    {
 | 
			
		||||
      MetaWaylandDataSource *data_source;
 | 
			
		||||
      uint32_t action = 0;
 | 
			
		||||
 | 
			
		||||
      data_source = compositor->seat->data_device.dnd_data_source;
 | 
			
		||||
 | 
			
		||||
@@ -1269,6 +1407,11 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
 | 
			
		||||
          meta_wayland_data_source_set_has_target (data_source,
 | 
			
		||||
                                                   (event->data.l[1] & 1) != 0);
 | 
			
		||||
 | 
			
		||||
          /* data.l[4] contains the action atom */
 | 
			
		||||
          if (event->data.l[4])
 | 
			
		||||
            action = atom_to_action ((Atom) event->data.l[4]);
 | 
			
		||||
 | 
			
		||||
          meta_wayland_data_source_set_current_action (data_source, action);
 | 
			
		||||
          return TRUE;
 | 
			
		||||
        }
 | 
			
		||||
      else if (event->message_type == xdnd_atoms[ATOM_DND_FINISHED])
 | 
			
		||||
@@ -1277,8 +1420,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
 | 
			
		||||
          if (compositor->seat->data_device.current_grab)
 | 
			
		||||
            return FALSE;
 | 
			
		||||
 | 
			
		||||
          meta_wayland_data_device_set_dnd_source (&compositor->seat->data_device,
 | 
			
		||||
                                                   NULL);
 | 
			
		||||
          meta_wayland_data_source_notify_finish (data_source);
 | 
			
		||||
          return TRUE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1290,7 +1432,8 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
 | 
			
		||||
      MetaWaylandDragGrab *drag_grab = compositor->seat->data_device.current_grab;
 | 
			
		||||
      MetaWaylandSurface *drag_focus = meta_wayland_drag_grab_get_focus (drag_grab);
 | 
			
		||||
 | 
			
		||||
      if (!drag_focus)
 | 
			
		||||
      if (!drag_focus &&
 | 
			
		||||
          event->message_type != xdnd_atoms[ATOM_DND_ENTER])
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
      if (event->message_type == xdnd_atoms[ATOM_DND_ENTER])
 | 
			
		||||
@@ -1338,6 +1481,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
 | 
			
		||||
        {
 | 
			
		||||
          ClutterEvent *motion;
 | 
			
		||||
          ClutterPoint pos;
 | 
			
		||||
          uint32_t action = 0;
 | 
			
		||||
 | 
			
		||||
          motion = clutter_event_new (CLUTTER_MOTION);
 | 
			
		||||
          clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
 | 
			
		||||
@@ -1346,11 +1490,13 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
 | 
			
		||||
          clutter_event_set_source_device (motion, seat->pointer.device);
 | 
			
		||||
          clutter_event_set_time (motion, dnd->last_motion_time);
 | 
			
		||||
 | 
			
		||||
          action = atom_to_action ((Atom) event->data.l[4]);
 | 
			
		||||
          meta_wayland_data_source_set_actions (dnd->selection.source, action);
 | 
			
		||||
 | 
			
		||||
          meta_wayland_surface_drag_dest_motion (drag_focus, motion);
 | 
			
		||||
          xdnd_send_status (compositor->xwayland_manager.selection_data,
 | 
			
		||||
                            (Window) event->data.l[0],
 | 
			
		||||
                            meta_wayland_data_source_has_target (
 | 
			
		||||
                              dnd->selection.source));
 | 
			
		||||
                            meta_wayland_data_source_get_current_action (dnd->selection.source));
 | 
			
		||||
 | 
			
		||||
          clutter_event_free (motion);
 | 
			
		||||
          return TRUE;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<protocol name="gtk">
 | 
			
		||||
 | 
			
		||||
  <interface name="gtk_shell" version="2">
 | 
			
		||||
  <interface name="gtk_shell" version="3">
 | 
			
		||||
    <description summary="gtk specific extensions">
 | 
			
		||||
      gtk_shell is a protocol extension providing additional features for
 | 
			
		||||
      clients implementing it. It is not backward compatible, and a client must
 | 
			
		||||
@@ -23,9 +23,13 @@
 | 
			
		||||
      <arg name="gtk_surface" type="new_id" interface="gtk_surface"/>
 | 
			
		||||
      <arg name="surface" type="object" interface="wl_surface"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="set_startup_id" since="3">
 | 
			
		||||
      <arg name="startup_id" type="string" allow-null="true"/>
 | 
			
		||||
    </request>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="gtk_surface" version="2">
 | 
			
		||||
  <interface name="gtk_surface" version="3">
 | 
			
		||||
    <request name="set_dbus_properties">
 | 
			
		||||
      <arg name="application_id" type="string" allow-null="true"/>
 | 
			
		||||
      <arg name="app_menu_path" type="string" allow-null="true"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,176 +0,0 @@
 | 
			
		||||
<protocol name="pointer_gestures">
 | 
			
		||||
  <interface name="_wl_pointer_gestures" version="1">
 | 
			
		||||
    <description summary="touchpad gestures">
 | 
			
		||||
      A global interface to provide semantic touchpad gestures for a given
 | 
			
		||||
      pointer.
 | 
			
		||||
 | 
			
		||||
      Two gestures are currently supported: swipe and zoom/rotate.
 | 
			
		||||
      All gestures follow a three-stage cycle: begin, update, end and
 | 
			
		||||
      are identified by a unique id.
 | 
			
		||||
 | 
			
		||||
      Warning! The protocol described in this file is experimental. Each
 | 
			
		||||
      version of this protocol should be considered incompatible with any
 | 
			
		||||
      other version, and a client binding to a version different to the one
 | 
			
		||||
      advertised will be terminated. Once the protocol is declared stable,
 | 
			
		||||
      compatibility is guaranteed, the '_' prefix will be removed from the
 | 
			
		||||
      name and the version will be reset to 1.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <enum name="error">
 | 
			
		||||
      <entry name="version_mismatch" value="0"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <request name="get_swipe_gesture">
 | 
			
		||||
      <description summary="get swipe gesture">
 | 
			
		||||
	Create a swipe gesture object. See the
 | 
			
		||||
	wl_pointer_gesture_swipe interface for details.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="id" type="new_id" interface="_wl_pointer_gesture_swipe"/>
 | 
			
		||||
      <arg name="pointer" type="object" interface="wl_pointer"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="get_pinch_gesture">
 | 
			
		||||
      <description summary="get pinch gesture">
 | 
			
		||||
	Create a pinch gesture object. See the
 | 
			
		||||
	wl_pointer_gesture_pinch interface for details.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="id" type="new_id" interface="_wl_pointer_gesture_pinch"/>
 | 
			
		||||
      <arg name="pointer" type="object" interface="wl_pointer"/>
 | 
			
		||||
    </request>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="_wl_pointer_gesture_swipe" version="1">
 | 
			
		||||
    <description summary="a swipe gesture object">
 | 
			
		||||
      A swipe gesture object notifies a client about a multi-finger swipe
 | 
			
		||||
      gesture detected on an indirect input device such as a touchpad.
 | 
			
		||||
      The gesture is usually initiated by multiple fingers moving in the
 | 
			
		||||
      same direction but once initiated the direction may change.
 | 
			
		||||
      The precise conditions of when such a gesture is detected are
 | 
			
		||||
      implementation-dependent.
 | 
			
		||||
 | 
			
		||||
      A gesture consists of three stages: begin, update (optional) and end.
 | 
			
		||||
      There cannot be multiple simultaneous pinch or swipe gestures on a
 | 
			
		||||
      same pointer/seat, how compositors prevent these situations is
 | 
			
		||||
      implementation-dependent.
 | 
			
		||||
 | 
			
		||||
      A gesture may be cancelled by the compositor or the hardware.
 | 
			
		||||
      Clients should not consider performing permanent or irreversible
 | 
			
		||||
      actions until the end of a gesture has been received.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <request name="destroy" type="destructor">
 | 
			
		||||
      <description summary="destroy the pointer swipe gesture object"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="begin">
 | 
			
		||||
      <description summary="multi-finger swipe begin">
 | 
			
		||||
	This event is sent when a multi-finger swipe gesture is detected
 | 
			
		||||
	on the device.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint"/>
 | 
			
		||||
      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
 | 
			
		||||
      <arg name="surface" type="object" interface="wl_surface"/>
 | 
			
		||||
      <arg name="fingers" type="uint" summary="number of fingers"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="update">
 | 
			
		||||
      <description summary="multi-finger swipe motion">
 | 
			
		||||
	This event is sent when a multi-finger swipe gesture changes the
 | 
			
		||||
	position of the logical center.
 | 
			
		||||
 | 
			
		||||
	The dx and dy coordinates are relative coordinates of the logical
 | 
			
		||||
	center of the gesture compared to the previous event.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
 | 
			
		||||
      <arg name="dx" type="fixed" summary="delta x coordinate in surface coordinate space"/>
 | 
			
		||||
      <arg name="dy" type="fixed" summary="delta y coordinate in surface coordinate space"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="end">
 | 
			
		||||
      <description summary="multi-finger swipe end">
 | 
			
		||||
	This event is sent when a multi-finger swipe gesture ceases to
 | 
			
		||||
	be valid. This may happen when one or more finger is lifted or
 | 
			
		||||
	the gesture is cancelled.
 | 
			
		||||
 | 
			
		||||
	When a gesture is cancelled, the client should undo state changes
 | 
			
		||||
	caused by this gesture. What causes a gesture to be cancelled is
 | 
			
		||||
	implementation-dependent.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint"/>
 | 
			
		||||
      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
 | 
			
		||||
      <arg name="cancelled" type="int" summary="1 if the gesture was cancelled, 0 otherwise"/>
 | 
			
		||||
    </event>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="_wl_pointer_gesture_pinch" version="1">
 | 
			
		||||
    <description summary="a pinch gesture object">
 | 
			
		||||
      A pinch gesture object notifies a client about a multi-finger pinch
 | 
			
		||||
      gesture detected on an indirect input device such as a touchpad.
 | 
			
		||||
      The gesture is usually initiated by multiple fingers moving towards
 | 
			
		||||
      each other or away from each other, or by two or more fingers rotating
 | 
			
		||||
      around a logical center of gravity.  The precise conditions of when
 | 
			
		||||
      such a gesture is detected are implementation-dependent.
 | 
			
		||||
 | 
			
		||||
      A gesture consists of three stages: begin, update (optional) and end.
 | 
			
		||||
      There cannot be multiple simultaneous pinch or swipe gestures on a
 | 
			
		||||
      same pointer/seat, how compositors prevent these situations is
 | 
			
		||||
      implementation-dependent.
 | 
			
		||||
 | 
			
		||||
      A gesture may be cancelled by the compositor or the hardware.
 | 
			
		||||
      Clients should not consider performing permanent or irreversible
 | 
			
		||||
      actions until the end of a gesture has been received.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <request name="destroy" type="destructor">
 | 
			
		||||
      <description summary="destroy the pinch gesture object"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="begin">
 | 
			
		||||
      <description summary="multi-finger pinch begin">
 | 
			
		||||
	This event is sent when a multi-finger pinch gesture is detected
 | 
			
		||||
	on the device.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint"/>
 | 
			
		||||
      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
 | 
			
		||||
      <arg name="surface" type="object" interface="wl_surface"/>
 | 
			
		||||
      <arg name="fingers" type="uint" summary="number of fingers"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="update">
 | 
			
		||||
      <description summary="multi-finger pinch motion">
 | 
			
		||||
	This event is sent when a multi-finger pinch gesture changes the
 | 
			
		||||
	position of the logical center, the rotation or the relative scale.
 | 
			
		||||
 | 
			
		||||
	The dx and dy coordinates are relative coordinates in the
 | 
			
		||||
	surface coordinate space of the logical center of the gesture.
 | 
			
		||||
 | 
			
		||||
	The scale factor is an absolute scale compared to the
 | 
			
		||||
	pointer_gesture_pinch.begin event, e.g. a scale of 2 means the fingers
 | 
			
		||||
	are now twice as far apart as on pointer_gesture_pinch.begin.
 | 
			
		||||
 | 
			
		||||
	The rotation is the relative angle in degrees clockwise compared to the previous
 | 
			
		||||
	pointer_gesture_pinch.begin or pointer_gesture_pinch.update event.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
 | 
			
		||||
      <arg name="dx" type="fixed" summary="delta x coordinate in surface coordinate space"/>
 | 
			
		||||
      <arg name="dy" type="fixed" summary="delta y coordinate in surface coordinate space"/>
 | 
			
		||||
      <arg name="scale" type="fixed" summary="scale relative to the initial finger position"/>
 | 
			
		||||
      <arg name="rotation" type="fixed" summary="angle in degrees cw relative to the previous event"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="end">
 | 
			
		||||
      <description summary="multi-finger pinch end">
 | 
			
		||||
	This event is sent when a multi-finger pinch gesture ceases to
 | 
			
		||||
	be valid. This may happen when one or more finger is lifted or
 | 
			
		||||
	the gesture is cancelled.
 | 
			
		||||
 | 
			
		||||
	When a gesture is cancelled, the client should undo state changes
 | 
			
		||||
	caused by this gesture. What causes a gesture to be cancelled is
 | 
			
		||||
	implementation-dependent.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint"/>
 | 
			
		||||
      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
 | 
			
		||||
      <arg name="cancelled" type="int" summary="1 if the gesture was cancelled, 0 otherwise"/>
 | 
			
		||||
    </event>
 | 
			
		||||
  </interface>
 | 
			
		||||
</protocol>
 | 
			
		||||
@@ -1,485 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<protocol name="xdg_shell">
 | 
			
		||||
 | 
			
		||||
  <copyright>
 | 
			
		||||
    Copyright © 2008-2013 Kristian Høgsberg
 | 
			
		||||
    Copyright © 2013      Rafael Antognolli
 | 
			
		||||
    Copyright © 2013      Jasper St. Pierre
 | 
			
		||||
    Copyright © 2010-2013 Intel Corporation
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
  </copyright>
 | 
			
		||||
 | 
			
		||||
  <interface name="xdg_shell" version="1">
 | 
			
		||||
    <description summary="create desktop-style surfaces">
 | 
			
		||||
      xdg_shell allows clients to turn a wl_surface into a "real window"
 | 
			
		||||
      which can be dragged, resized, stacked, and moved around by the
 | 
			
		||||
      user. Everything about this interface is suited towards traditional
 | 
			
		||||
      desktop environments.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <enum name="version">
 | 
			
		||||
      <description summary="latest protocol version">
 | 
			
		||||
	The 'current' member of this enum gives the version of the
 | 
			
		||||
	protocol.  Implementations can compare this to the version
 | 
			
		||||
	they implement using static_assert to ensure the protocol and
 | 
			
		||||
	implementation versions match.
 | 
			
		||||
      </description>
 | 
			
		||||
      <entry name="current" value="5" summary="Always the latest version"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <enum name="error">
 | 
			
		||||
      <entry name="role" value="0" summary="given wl_surface has another role"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <request name="destroy" type="destructor">
 | 
			
		||||
      <description summary="destroy xdg_shell">
 | 
			
		||||
        Destroy this xdg_shell object.
 | 
			
		||||
 | 
			
		||||
        Destroying a bound xdg_shell object while there are surfaces
 | 
			
		||||
        still alive with roles from this interface is illegal and will
 | 
			
		||||
        result in a protocol error. Make sure to destroy all surfaces
 | 
			
		||||
        before destroying this object.
 | 
			
		||||
      </description>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="use_unstable_version">
 | 
			
		||||
      <description summary="enable use of this unstable version">
 | 
			
		||||
	Negotiate the unstable version of the interface.  This
 | 
			
		||||
	mechanism is in place to ensure client and server agree on the
 | 
			
		||||
	unstable versions of the protocol that they speak or exit
 | 
			
		||||
	cleanly if they don't agree.  This request will go away once
 | 
			
		||||
	the xdg-shell protocol is stable.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="version" type="int"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="get_xdg_surface">
 | 
			
		||||
      <description summary="create a shell surface from a surface">
 | 
			
		||||
	This creates an xdg_surface for the given surface and gives it the
 | 
			
		||||
	xdg_surface role. See the documentation of xdg_surface for more details.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="id" type="new_id" interface="xdg_surface"/>
 | 
			
		||||
      <arg name="surface" type="object" interface="wl_surface"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="get_xdg_popup">
 | 
			
		||||
      <description summary="create a popup for a surface">
 | 
			
		||||
	This creates an xdg_popup for the given surface and gives it the
 | 
			
		||||
	xdg_popup role. See the documentation of xdg_popup for more details.
 | 
			
		||||
 | 
			
		||||
	This request must be used in response to some sort of user action
 | 
			
		||||
	like a button press, key press, or touch down event.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="id" type="new_id" interface="xdg_popup"/>
 | 
			
		||||
      <arg name="surface" type="object" interface="wl_surface"/>
 | 
			
		||||
      <arg name="parent" type="object" interface="wl_surface"/>
 | 
			
		||||
      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 | 
			
		||||
      <arg name="serial" type="uint" summary="the serial of the user event"/>
 | 
			
		||||
      <arg name="x" type="int"/>
 | 
			
		||||
      <arg name="y" type="int"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="ping">
 | 
			
		||||
      <description summary="check if the client is alive">
 | 
			
		||||
        The ping event asks the client if it's still alive. Pass the
 | 
			
		||||
        serial specified in the event back to the compositor by sending
 | 
			
		||||
        a "pong" request back with the specified serial.
 | 
			
		||||
 | 
			
		||||
        Compositors can use this to determine if the client is still
 | 
			
		||||
        alive. It's unspecified what will happen if the client doesn't
 | 
			
		||||
        respond to the ping request, or in what timeframe. Clients should
 | 
			
		||||
        try to respond in a reasonable amount of time.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint" summary="pass this to the pong request"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <request name="pong">
 | 
			
		||||
      <description summary="respond to a ping event">
 | 
			
		||||
	A client must respond to a ping event with a pong request or
 | 
			
		||||
	the client may be deemed unresponsive.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint" summary="serial of the ping event"/>
 | 
			
		||||
    </request>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="xdg_surface" version="1">
 | 
			
		||||
    <description summary="A desktop window">
 | 
			
		||||
      An interface that may be implemented by a wl_surface, for
 | 
			
		||||
      implementations that provide a desktop-style user interface.
 | 
			
		||||
 | 
			
		||||
      It provides requests to treat surfaces like windows, allowing to set
 | 
			
		||||
      properties like maximized, fullscreen, minimized, and to move and resize
 | 
			
		||||
      them, and associate metadata like title and app id.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <request name="destroy" type="destructor">
 | 
			
		||||
      <description summary="Destroy the xdg_surface">
 | 
			
		||||
	Unmap and destroy the window. The window will be effectively
 | 
			
		||||
	hidden from the user's point of view, and all state like
 | 
			
		||||
	maximization, fullscreen, and so on, will be lost.
 | 
			
		||||
      </description>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="set_parent">
 | 
			
		||||
      <description summary="set the parent of this surface">
 | 
			
		||||
	Set the "parent" of this surface. This window should be stacked
 | 
			
		||||
	above a parent. The parent surface must be mapped as long as this
 | 
			
		||||
	surface is mapped.
 | 
			
		||||
 | 
			
		||||
	Parent windows should be set on dialogs, toolboxes, or other
 | 
			
		||||
	"auxilliary" surfaces, so that the parent is raised when the dialog
 | 
			
		||||
	is raised.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="parent" type="object" interface="xdg_surface" allow-null="true"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="set_title">
 | 
			
		||||
      <description summary="set surface title">
 | 
			
		||||
	Set a short title for the surface.
 | 
			
		||||
 | 
			
		||||
	This string may be used to identify the surface in a task bar,
 | 
			
		||||
	window list, or other user interface elements provided by the
 | 
			
		||||
	compositor.
 | 
			
		||||
 | 
			
		||||
	The string must be encoded in UTF-8.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="title" type="string"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="set_app_id">
 | 
			
		||||
      <description summary="set application ID">
 | 
			
		||||
	Set an application identifier for the surface.
 | 
			
		||||
 | 
			
		||||
	The app ID identifies the general class of applications to which
 | 
			
		||||
	the surface belongs. The compositor can use this to group multiple
 | 
			
		||||
	applications together, or to determine how to launch a new
 | 
			
		||||
	application.
 | 
			
		||||
 | 
			
		||||
	See the desktop-entry specification [0] for more details on
 | 
			
		||||
	application identifiers and how they relate to well-known DBus
 | 
			
		||||
	names and .desktop files.
 | 
			
		||||
 | 
			
		||||
	[0] http://standards.freedesktop.org/desktop-entry-spec/
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="app_id" type="string"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="show_window_menu">
 | 
			
		||||
      <description summary="show the window menu">
 | 
			
		||||
        Clients implementing client-side decorations might want to show
 | 
			
		||||
        a context menu when right-clicking on the decorations, giving the
 | 
			
		||||
        user a menu that they can use to maximize or minimize the window.
 | 
			
		||||
 | 
			
		||||
        This request asks the compositor to pop up such a window menu at
 | 
			
		||||
        the given position, relative to the local surface coordinates of
 | 
			
		||||
        the parent surface. There are no guarantees as to what menu items
 | 
			
		||||
        the window menu contains.
 | 
			
		||||
 | 
			
		||||
        This request must be used in response to some sort of user action
 | 
			
		||||
        like a button press, key press, or touch down event.
 | 
			
		||||
      </description>
 | 
			
		||||
 | 
			
		||||
      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 | 
			
		||||
      <arg name="serial" type="uint" summary="the serial of the user event"/>
 | 
			
		||||
      <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
 | 
			
		||||
      <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="move">
 | 
			
		||||
      <description summary="start an interactive move">
 | 
			
		||||
	Start an interactive, user-driven move of the surface.
 | 
			
		||||
 | 
			
		||||
	This request must be used in response to some sort of user action
 | 
			
		||||
	like a button press, key press, or touch down event.
 | 
			
		||||
 | 
			
		||||
	The server may ignore move requests depending on the state of
 | 
			
		||||
	the surface (e.g. fullscreen or maximized).
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 | 
			
		||||
      <arg name="serial" type="uint" summary="the serial of the user event"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <enum name="resize_edge">
 | 
			
		||||
      <description summary="edge values for resizing">
 | 
			
		||||
	These values are used to indicate which edge of a surface
 | 
			
		||||
	is being dragged in a resize operation. The server may
 | 
			
		||||
	use this information to adapt its behavior, e.g. choose
 | 
			
		||||
	an appropriate cursor image.
 | 
			
		||||
      </description>
 | 
			
		||||
      <entry name="none" value="0"/>
 | 
			
		||||
      <entry name="top" value="1"/>
 | 
			
		||||
      <entry name="bottom" value="2"/>
 | 
			
		||||
      <entry name="left" value="4"/>
 | 
			
		||||
      <entry name="top_left" value="5"/>
 | 
			
		||||
      <entry name="bottom_left" value="6"/>
 | 
			
		||||
      <entry name="right" value="8"/>
 | 
			
		||||
      <entry name="top_right" value="9"/>
 | 
			
		||||
      <entry name="bottom_right" value="10"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <request name="resize">
 | 
			
		||||
      <description summary="start an interactive resize">
 | 
			
		||||
	Start a user-driven, interactive resize of the surface.
 | 
			
		||||
 | 
			
		||||
	This request must be used in response to some sort of user action
 | 
			
		||||
	like a button press, key press, or touch down event.
 | 
			
		||||
 | 
			
		||||
	The server may ignore resize requests depending on the state of
 | 
			
		||||
	the surface (e.g. fullscreen or maximized).
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 | 
			
		||||
      <arg name="serial" type="uint" summary="the serial of the user event"/>
 | 
			
		||||
      <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <enum name="state">
 | 
			
		||||
      <description summary="types of state on the surface">
 | 
			
		||||
        The different state values used on the surface. This is designed for
 | 
			
		||||
        state values like maximized, fullscreen. It is paired with the
 | 
			
		||||
        configure event to ensure that both the client and the compositor
 | 
			
		||||
        setting the state can be synchronized.
 | 
			
		||||
 | 
			
		||||
        States set in this way are double-buffered. They will get applied on
 | 
			
		||||
        the next commit.
 | 
			
		||||
 | 
			
		||||
        Desktop environments may extend this enum by taking up a range of
 | 
			
		||||
        values and documenting the range they chose in this description.
 | 
			
		||||
        They are not required to document the values for the range that they
 | 
			
		||||
        chose. Ideally, any good extensions from a desktop environment should
 | 
			
		||||
        make its way into standardization into this enum.
 | 
			
		||||
 | 
			
		||||
        The current reserved ranges are:
 | 
			
		||||
 | 
			
		||||
        0x0000 - 0x0FFF: xdg-shell core values, documented below.
 | 
			
		||||
        0x1000 - 0x1FFF: GNOME
 | 
			
		||||
      </description>
 | 
			
		||||
      <entry name="maximized" value="1" summary="the surface is maximized">
 | 
			
		||||
        The surface is maximized. The window geometry specified in the configure
 | 
			
		||||
        event must be obeyed by the client.
 | 
			
		||||
      </entry>
 | 
			
		||||
      <entry name="fullscreen" value="2" summary="the surface is fullscreen">
 | 
			
		||||
        The surface is fullscreen. The window geometry specified in the configure
 | 
			
		||||
        event must be obeyed by the client.
 | 
			
		||||
      </entry>
 | 
			
		||||
      <entry name="resizing" value="3">
 | 
			
		||||
        The surface is being resized. The window geometry specified in the
 | 
			
		||||
        configure event is a maximum; the client cannot resize beyond it.
 | 
			
		||||
        Clients that have aspect ratio or cell sizing configuration can use
 | 
			
		||||
        a smaller size, however.
 | 
			
		||||
      </entry>
 | 
			
		||||
      <entry name="activated" value="4">
 | 
			
		||||
        Client window decorations should be painted as if the window is
 | 
			
		||||
        active. Do not assume this means that the window actually has
 | 
			
		||||
        keyboard or pointer focus.
 | 
			
		||||
      </entry>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <event name="configure">
 | 
			
		||||
      <description summary="suggest a surface change">
 | 
			
		||||
	The configure event asks the client to resize its surface or to
 | 
			
		||||
	change its state.
 | 
			
		||||
 | 
			
		||||
	The width and height arguments specify a hint to the window
 | 
			
		||||
	about how its surface should be resized in window geometry
 | 
			
		||||
	coordinates.
 | 
			
		||||
 | 
			
		||||
	The states listed in the event specify how the width/height
 | 
			
		||||
	arguments should be interpreted, and possibly how it should be
 | 
			
		||||
	drawn.
 | 
			
		||||
 | 
			
		||||
	Clients should arrange their surface for the new size and
 | 
			
		||||
	states, and then send a ack_configure request with the serial
 | 
			
		||||
	sent in this configure event at some point before committing
 | 
			
		||||
	the new surface.
 | 
			
		||||
 | 
			
		||||
	If the client receives multiple configure events before it
 | 
			
		||||
        can respond to one, it is free to discard all but the last
 | 
			
		||||
        event it received.
 | 
			
		||||
      </description>
 | 
			
		||||
 | 
			
		||||
      <arg name="width" type="int"/>
 | 
			
		||||
      <arg name="height" type="int"/>
 | 
			
		||||
      <arg name="states" type="array"/>
 | 
			
		||||
      <arg name="serial" type="uint"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <request name="ack_configure">
 | 
			
		||||
      <description summary="ack a configure event">
 | 
			
		||||
        When a configure event is received, if a client commits the
 | 
			
		||||
        surface in response to the configure event, then the client
 | 
			
		||||
        must make a ack_configure request before the commit request,
 | 
			
		||||
        passing along the serial of the configure event.
 | 
			
		||||
 | 
			
		||||
        The compositor might use this information to move a surface
 | 
			
		||||
        to the top left only when the client has drawn itself for
 | 
			
		||||
        the maximized or fullscreen state.
 | 
			
		||||
 | 
			
		||||
        If the client receives multiple configure events before it
 | 
			
		||||
        can respond to one, it only has to ack the last configure event.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="serial" type="uint" summary="the serial from the configure event"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="set_window_geometry">
 | 
			
		||||
      <description summary="set the new window geometry">
 | 
			
		||||
        The window geometry of a window is its "visible bounds" from the
 | 
			
		||||
        user's perspective. Client-side decorations often have invisible
 | 
			
		||||
        portions like drop-shadows which should be ignored for the
 | 
			
		||||
        purposes of aligning, placing and constraining windows.
 | 
			
		||||
 | 
			
		||||
        Once the window geometry of the surface is set once, it is not
 | 
			
		||||
        possible to unset it, and it will remain the same until
 | 
			
		||||
        set_window_geometry is called again, even if a new subsurface or
 | 
			
		||||
        buffer is attached.
 | 
			
		||||
 | 
			
		||||
        If never set, the value is the full bounds of the surface,
 | 
			
		||||
        including any subsurfaces. This updates dynamically on every
 | 
			
		||||
        commit. This unset mode is meant for extremely simple clients.
 | 
			
		||||
 | 
			
		||||
        If responding to a configure event, the window geometry in here
 | 
			
		||||
        must respect the sizing negotiations specified by the states in
 | 
			
		||||
        the configure event.
 | 
			
		||||
 | 
			
		||||
        The width and height must be greater than zero.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="x" type="int"/>
 | 
			
		||||
      <arg name="y" type="int"/>
 | 
			
		||||
      <arg name="width" type="int"/>
 | 
			
		||||
      <arg name="height" type="int"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <request name="set_maximized" />
 | 
			
		||||
    <request name="unset_maximized" />
 | 
			
		||||
 | 
			
		||||
    <request name="set_fullscreen">
 | 
			
		||||
      <description summary="set the window as fullscreen on a monitor">
 | 
			
		||||
	Make the surface fullscreen.
 | 
			
		||||
 | 
			
		||||
        You can specify an output that you would prefer to be fullscreen.
 | 
			
		||||
	If this value is NULL, it's up to the compositor to choose which
 | 
			
		||||
        display will be used to map this surface.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
 | 
			
		||||
    </request>
 | 
			
		||||
    <request name="unset_fullscreen" />
 | 
			
		||||
 | 
			
		||||
    <request name="set_minimized">
 | 
			
		||||
      <description summary="set the window as minimized">
 | 
			
		||||
	Request that the compositor minimize your surface. There is no
 | 
			
		||||
	way to know if the surface is currently minimized, nor is there
 | 
			
		||||
	any way to unset minimization on this surface.
 | 
			
		||||
 | 
			
		||||
	If you are looking to throttle redrawing when minimized, please
 | 
			
		||||
	instead use the wl_surface.frame event for this, as this will
 | 
			
		||||
	also work with live previews on windows in Alt-Tab, Expose or
 | 
			
		||||
	similar compositor features.
 | 
			
		||||
      </description>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="close">
 | 
			
		||||
      <description summary="surface wants to be closed">
 | 
			
		||||
        The close event is sent by the compositor when the user
 | 
			
		||||
        wants the surface to be closed. This should be equivalent to
 | 
			
		||||
        the user clicking the close button in client-side decorations,
 | 
			
		||||
        if your application has any...
 | 
			
		||||
 | 
			
		||||
        This is only a request that the user intends to close your
 | 
			
		||||
        window. The client may choose to ignore this request, or show
 | 
			
		||||
        a dialog to ask the user to save their data...
 | 
			
		||||
      </description>
 | 
			
		||||
    </event>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="xdg_popup" version="1">
 | 
			
		||||
    <description summary="short-lived, popup surfaces for menus">
 | 
			
		||||
      A popup surface is a short-lived, temporary surface that can be
 | 
			
		||||
      used to implement menus. It takes an explicit grab on the surface
 | 
			
		||||
      that will be dismissed when the user dismisses the popup. This can
 | 
			
		||||
      be done by the user clicking outside the surface, using the keyboard,
 | 
			
		||||
      or even locking the screen through closing the lid or a timeout.
 | 
			
		||||
 | 
			
		||||
      When the popup is dismissed, a popup_done event will be sent out,
 | 
			
		||||
      and at the same time the surface will be unmapped. The xdg_popup
 | 
			
		||||
      object is now inert and cannot be reactivated, so clients should
 | 
			
		||||
      destroy it. Explicitly destroying the xdg_popup object will also
 | 
			
		||||
      dismiss the popup and unmap the surface.
 | 
			
		||||
 | 
			
		||||
      Clients will receive events for all their surfaces during this
 | 
			
		||||
      grab (which is an "owner-events" grab in X11 parlance). This is
 | 
			
		||||
      done so that users can navigate through submenus and other
 | 
			
		||||
      "nested" popup windows without having to dismiss the topmost
 | 
			
		||||
      popup.
 | 
			
		||||
 | 
			
		||||
      Clients that want to dismiss the popup when another surface of
 | 
			
		||||
      their own is clicked should dismiss the popup using the destroy
 | 
			
		||||
      request.
 | 
			
		||||
 | 
			
		||||
      The parent surface must have either an xdg_surface or xdg_popup
 | 
			
		||||
      role.
 | 
			
		||||
 | 
			
		||||
      Specifying an xdg_popup for the parent means that the popups are
 | 
			
		||||
      nested, with this popup now being the topmost popup. Nested
 | 
			
		||||
      popups must be destroyed in the reverse order they were created
 | 
			
		||||
      in, e.g. the only popup you are allowed to destroy at all times
 | 
			
		||||
      is the topmost one.
 | 
			
		||||
 | 
			
		||||
      If there is an existing popup when creating a new popup, the
 | 
			
		||||
      parent must be the current topmost popup.
 | 
			
		||||
 | 
			
		||||
      A parent surface must be mapped before the new popup is mapped.
 | 
			
		||||
 | 
			
		||||
      When compositors choose to dismiss a popup, they will likely
 | 
			
		||||
      dismiss every nested popup as well.
 | 
			
		||||
 | 
			
		||||
      The x and y arguments specify where the top left of the popup
 | 
			
		||||
      should be placed, relative to the local surface coordinates of the
 | 
			
		||||
      parent surface.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <enum name="error">
 | 
			
		||||
      <description summary="xdg_popup error values">
 | 
			
		||||
	These errors can be emitted in response to xdg_popup requests.
 | 
			
		||||
      </description>
 | 
			
		||||
      <entry name="not_the_topmost_popup" value="0" summary="The client tried to map or destroy a non-toplevel popup"/>
 | 
			
		||||
      <entry name="invalid_parent" value="1" summary="The client specified an invalid parent surface"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <request name="destroy" type="destructor">
 | 
			
		||||
      <description summary="remove xdg_popup interface">
 | 
			
		||||
	This destroys the popup. Explicitly destroying the xdg_popup
 | 
			
		||||
	object will also dismiss the popup, and unmap the surface.
 | 
			
		||||
 | 
			
		||||
	If this xdg_popup is not the "topmost" popup, a protocol error
 | 
			
		||||
	will be sent.
 | 
			
		||||
      </description>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="popup_done">
 | 
			
		||||
      <description summary="popup interaction is done">
 | 
			
		||||
	The popup_done event is sent out when a popup is dismissed
 | 
			
		||||
	by the compositor.
 | 
			
		||||
      </description>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
  </interface>
 | 
			
		||||
</protocol>
 | 
			
		||||
@@ -1671,13 +1671,12 @@ meta_display_handle_xevent (MetaDisplay *display,
 | 
			
		||||
  meta_spew_event_print (display, event);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STARTUP_NOTIFICATION
 | 
			
		||||
  if (sn_display_process_event (display->sn_display, event))
 | 
			
		||||
  if (meta_startup_notification_handle_xevent (display->startup_notification,
 | 
			
		||||
                                               event))
 | 
			
		||||
    {
 | 
			
		||||
      bypass_gtk = bypass_compositor = TRUE;
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor () &&
 | 
			
		||||
 
 | 
			
		||||
@@ -182,6 +182,8 @@ argbdata_to_surface (gulong *argb_data, int w, int h)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  cairo_surface_mark_dirty (surface);
 | 
			
		||||
 | 
			
		||||
  return surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1843,7 +1843,7 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
 | 
			
		||||
    { display->atom__NET_WM_WINDOW_TYPE, META_PROP_VALUE_ATOM_LIST, reload_net_wm_window_type, LOAD_INIT | INCLUDE_OR | FORCE_INIT },
 | 
			
		||||
    { display->atom__NET_WM_STRUT,         META_PROP_VALUE_INVALID, reload_struts, NONE },
 | 
			
		||||
    { display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts, NONE },
 | 
			
		||||
    { display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL,  reload_bypass_compositor, NONE },
 | 
			
		||||
    { display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL,  reload_bypass_compositor, LOAD_INIT | INCLUDE_OR },
 | 
			
		||||
    { display->atom__NET_WM_WINDOW_OPACITY, META_PROP_VALUE_CARDINAL, reload_window_opacity, LOAD_INIT | INCLUDE_OR },
 | 
			
		||||
    { 0 },
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -389,7 +389,7 @@ meta_window_apply_session_info (MetaWindow *window,
 | 
			
		||||
                  "Restoring minimized state %d for window %s\n",
 | 
			
		||||
                  info->minimized, window->desc);
 | 
			
		||||
 | 
			
		||||
      if (window->has_minimize_func && info->minimized)
 | 
			
		||||
      if (info->minimized)
 | 
			
		||||
        meta_window_minimize (window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -542,13 +542,10 @@ meta_window_x11_manage (MetaWindow *window)
 | 
			
		||||
   * For normal windows, do a full ConfigureRequest based on the
 | 
			
		||||
   * window hints, as that's what the ICCCM says to do.
 | 
			
		||||
   */
 | 
			
		||||
  priv->client_rect = window->rect;
 | 
			
		||||
  window->buffer_rect = window->rect;
 | 
			
		||||
 | 
			
		||||
  if (window->override_redirect)
 | 
			
		||||
    {
 | 
			
		||||
      priv->client_rect = window->rect;
 | 
			
		||||
      window->buffer_rect = window->rect;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
  if (!window->override_redirect)
 | 
			
		||||
    {
 | 
			
		||||
      MetaRectangle rect;
 | 
			
		||||
      MetaMoveResizeFlags flags;
 | 
			
		||||
@@ -863,7 +860,7 @@ meta_window_x11_grab_op_began (MetaWindow *window,
 | 
			
		||||
      if (window->sync_request_counter != None)
 | 
			
		||||
        meta_window_x11_create_sync_request_alarm (window);
 | 
			
		||||
 | 
			
		||||
      if (window->size_hints.width_inc > 1 || window->size_hints.height_inc > 1)
 | 
			
		||||
      if (window->size_hints.width_inc > 2 || window->size_hints.height_inc > 2)
 | 
			
		||||
        {
 | 
			
		||||
          priv->showing_resize_popup = TRUE;
 | 
			
		||||
          meta_window_refresh_resize_popup (window);
 | 
			
		||||
@@ -1735,9 +1732,9 @@ meta_window_x11_update_input_region (MetaWindow *window)
 | 
			
		||||
          region = cairo_region_create ();
 | 
			
		||||
        }
 | 
			
		||||
      else if (n_rects == 1 &&
 | 
			
		||||
               (rects[0].x == 0 ||
 | 
			
		||||
                rects[0].y == 0 ||
 | 
			
		||||
                rects[0].width == priv->client_rect.width ||
 | 
			
		||||
               (rects[0].x == 0 &&
 | 
			
		||||
                rects[0].y == 0 &&
 | 
			
		||||
                rects[0].width == priv->client_rect.width &&
 | 
			
		||||
                rects[0].height == priv->client_rect.height))
 | 
			
		||||
        {
 | 
			
		||||
          /* This is the bounding region case. Keep the
 | 
			
		||||
@@ -1850,6 +1847,12 @@ meta_window_x11_update_shape_region (MetaWindow *window)
 | 
			
		||||
       * this is simply the client area.
 | 
			
		||||
       */
 | 
			
		||||
      cairo_region_intersect_rectangle (region, &client_area);
 | 
			
		||||
 | 
			
		||||
      /* Some applications might explicitly set their bounding region
 | 
			
		||||
       * to the client area. Detect these cases, and throw out the
 | 
			
		||||
       * bounding region in this case. */
 | 
			
		||||
      if (cairo_region_contains_rectangle (region, &client_area) == CAIRO_REGION_OVERLAP_IN)
 | 
			
		||||
        g_clear_pointer (®ion, cairo_region_destroy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  meta_window_set_shape_region (window, region);
 | 
			
		||||
@@ -2441,8 +2444,7 @@ meta_window_x11_client_message (MetaWindow *window,
 | 
			
		||||
    {
 | 
			
		||||
      meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n",
 | 
			
		||||
                    event->xclient.data.l[0]);
 | 
			
		||||
      if (event->xclient.data.l[0] == IconicState &&
 | 
			
		||||
          window->has_minimize_func)
 | 
			
		||||
      if (event->xclient.data.l[0] == IconicState)
 | 
			
		||||
        meta_window_minimize (window);
 | 
			
		||||
 | 
			
		||||
      return TRUE;
 | 
			
		||||
 
 | 
			
		||||
@@ -194,6 +194,7 @@ async_get_property_finish (xcb_connection_t          *xcb_conn,
 | 
			
		||||
{
 | 
			
		||||
  xcb_get_property_reply_t *reply;
 | 
			
		||||
  xcb_generic_error_t *error;
 | 
			
		||||
  int length;
 | 
			
		||||
 | 
			
		||||
  reply = xcb_get_property_reply (xcb_conn, cookie, &error);
 | 
			
		||||
  if (error)
 | 
			
		||||
@@ -209,8 +210,15 @@ async_get_property_finish (xcb_connection_t          *xcb_conn,
 | 
			
		||||
  results->prop = NULL;
 | 
			
		||||
 | 
			
		||||
  if (results->type != None)
 | 
			
		||||
    results->prop = g_memdup (xcb_get_property_value (reply),
 | 
			
		||||
                              xcb_get_property_value_length (reply));
 | 
			
		||||
    {
 | 
			
		||||
      length = xcb_get_property_value_length (reply);
 | 
			
		||||
      /* Leave room for a trailing '\0' since xcb doesn't return null-terminated
 | 
			
		||||
       * strings
 | 
			
		||||
       */
 | 
			
		||||
      results->prop = g_malloc (length + 1);
 | 
			
		||||
      memcpy (results->prop, xcb_get_property_value (reply), length);
 | 
			
		||||
      results->prop[length] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  free (reply);
 | 
			
		||||
  return (results->prop != NULL);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user