Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
35729e8659 | ||
![]() |
dc7e665de9 | ||
![]() |
2e3bfd1a11 | ||
![]() |
b7aca07844 | ||
![]() |
dc780d2c44 | ||
![]() |
c49b284643 | ||
![]() |
0373b854c1 | ||
![]() |
5d837a5c85 | ||
![]() |
79c86ae890 | ||
![]() |
7c7cf91c32 | ||
![]() |
e407f5bbae | ||
![]() |
8900bd2f5c | ||
![]() |
83c17134f1 | ||
![]() |
8e5fb03611 | ||
![]() |
dece49b53d | ||
![]() |
443d579d40 | ||
![]() |
5066eaf691 | ||
![]() |
6ea7fa9973 | ||
![]() |
79f755bf0f | ||
![]() |
1845bfe1b6 | ||
![]() |
8e22bf5bc9 | ||
![]() |
c13ddafdb8 | ||
![]() |
94513726de | ||
![]() |
0aa4c4d43e | ||
![]() |
e3db4ab16a | ||
![]() |
614d6bd0f8 | ||
![]() |
1d56d50fcd | ||
![]() |
0ffd4254d9 | ||
![]() |
36eee04a21 | ||
![]() |
d3fdaa3232 | ||
![]() |
165050f8f9 | ||
![]() |
68279e8a08 | ||
![]() |
cd1ce2cb0a | ||
![]() |
b01f95cfdd | ||
![]() |
4b667d1e09 | ||
![]() |
fe8454d13f | ||
![]() |
53a6d16891 | ||
![]() |
e76c3ecb00 | ||
![]() |
637be80c86 | ||
![]() |
975feb9202 | ||
![]() |
a5417ebee1 | ||
![]() |
b64b159109 | ||
![]() |
804ab7894f | ||
![]() |
299ed424d3 | ||
![]() |
55692b4019 | ||
![]() |
2fafa24305 | ||
![]() |
51a2f28723 | ||
![]() |
e11feb229b | ||
![]() |
1ee387bb31 | ||
![]() |
cba2ab445e | ||
![]() |
038f828ab1 | ||
![]() |
4dc5882777 | ||
![]() |
b0b08d5010 | ||
![]() |
070cd27786 | ||
![]() |
9df6cda3e3 | ||
![]() |
39763d4add | ||
![]() |
352cac3850 | ||
![]() |
9c745105f8 | ||
![]() |
ab9dabe725 | ||
![]() |
7ce06928e2 | ||
![]() |
ac79988939 | ||
![]() |
a43a2af18b | ||
![]() |
07f533f617 | ||
![]() |
10504b0fdc |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -66,6 +66,8 @@ src/gtk-shell-protocol.c
|
|||||||
src/gtk-shell-server-protocol.h
|
src/gtk-shell-server-protocol.h
|
||||||
src/xdg-shell-protocol.c
|
src/xdg-shell-protocol.c
|
||||||
src/xdg-shell-server-protocol.h
|
src/xdg-shell-server-protocol.h
|
||||||
|
src/pointer-gestures-protocol.c
|
||||||
|
src/pointer-gestures-server-protocol.h
|
||||||
src/xserver-protocol.c
|
src/xserver-protocol.c
|
||||||
src/xserver-server-protocol.h
|
src/xserver-server-protocol.h
|
||||||
src/meta/meta-version.h
|
src/meta/meta-version.h
|
||||||
|
50
NEWS
50
NEWS
@@ -1,3 +1,53 @@
|
|||||||
|
3.18.0
|
||||||
|
======
|
||||||
|
* Misc. fixes [Florian, Jonas; #753434]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jonas Ådahl, Florian Müllner
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Rūdolfs Mazurs [lv]
|
||||||
|
|
||||||
|
3.17.92
|
||||||
|
=======
|
||||||
|
* Don't omit the background color for backgrounds that don't fill the screen
|
||||||
|
[Ray; #754476]
|
||||||
|
* Fix up key state on FocusIn when running nested [Owen; #753948]
|
||||||
|
* Find the right DRM device instead of hardcoding card0 [Marek; #753434]
|
||||||
|
* Scale cursor on HiDPI screens [Jonas; #744932]
|
||||||
|
* Misc. fixes and cleanups [Lan, Jonas, Javier, Olivier; #754545, #754215,
|
||||||
|
#754621, #754715]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jonas Ådahl, Marek Chalupa, Olivier Fourdan, Javier Jardón, Ting-Wei Lan,
|
||||||
|
Ray Strode, Owen W. Taylor
|
||||||
|
|
||||||
|
3.17.91
|
||||||
|
=======
|
||||||
|
* Send error on pointer-gesture protocol version mismatch [Jonas; #753855]
|
||||||
|
* Misc. cleanups [Jonas; #744932]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jonas Ådahl
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Chao-Hsiung Liao [zh_TW], Piotr Drąg [pl]
|
||||||
|
|
||||||
|
3.17.90
|
||||||
|
=======
|
||||||
|
* Fix glitch with some fullscreen apps [Rui; #753020]
|
||||||
|
* Fix screen update issue with NVidia driver [Aaron, Rui; #728464]
|
||||||
|
* Only call frame callbacks for surfaces that get drawn [Adel; #739163]
|
||||||
|
* Misc. bug fixes and cleanups [Jonas, Rui, Ting-Wei; #753222, #752753, #753237,
|
||||||
|
#753380, #744104, #744932]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jonas Ådahl, Adel Gadllah, Carlos Garnacho, Ting-Wei Lan, Rui Matos,
|
||||||
|
Florian Müllner, Aaron Plattner, Jasper St. Pierre
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Akom Chotiphantawanon [th]
|
||||||
|
|
||||||
3.17.4
|
3.17.4
|
||||||
======
|
======
|
||||||
* nested: Allow basic configuration of dummy outputs [Jonas; #747089]
|
* nested: Allow basic configuration of dummy outputs [Jonas; #747089]
|
||||||
|
11
configure.ac
11
configure.ac
@@ -1,8 +1,8 @@
|
|||||||
AC_PREREQ(2.62)
|
AC_PREREQ(2.62)
|
||||||
|
|
||||||
m4_define([mutter_major_version], [3])
|
m4_define([mutter_major_version], [3])
|
||||||
m4_define([mutter_minor_version], [17])
|
m4_define([mutter_minor_version], [18])
|
||||||
m4_define([mutter_micro_version], [4])
|
m4_define([mutter_micro_version], [0])
|
||||||
|
|
||||||
m4_define([mutter_version],
|
m4_define([mutter_version],
|
||||||
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
||||||
@@ -63,7 +63,7 @@ MUTTER_PC_MODULES="
|
|||||||
pango >= 1.2.0
|
pango >= 1.2.0
|
||||||
cairo >= 1.10.0
|
cairo >= 1.10.0
|
||||||
gsettings-desktop-schemas >= 3.15.92
|
gsettings-desktop-schemas >= 3.15.92
|
||||||
$CLUTTER_PACKAGE >= 1.21.3
|
$CLUTTER_PACKAGE >= 1.23.4
|
||||||
cogl-1.0 >= 1.17.1
|
cogl-1.0 >= 1.17.1
|
||||||
upower-glib >= 0.99.0
|
upower-glib >= 0.99.0
|
||||||
gnome-desktop-3.0
|
gnome-desktop-3.0
|
||||||
@@ -319,6 +319,11 @@ if test "x$enable_debug" = "xyes"; then
|
|||||||
CFLAGS="$CFLAGS -g -O"
|
CFLAGS="$CFLAGS -g -O"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_CHECK_DECL([GL_EXT_x11_sync_object],
|
||||||
|
[],
|
||||||
|
[AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])],
|
||||||
|
[#include <GL/glx.h>])
|
||||||
|
|
||||||
#### Warnings (last since -Werror can disturb other tests)
|
#### Warnings (last since -Werror can disturb other tests)
|
||||||
|
|
||||||
# Stay command-line compatible with the gnome-common configure option. Here
|
# Stay command-line compatible with the gnome-common configure option. Here
|
||||||
|
51
po/pl.po
51
po/pl.po
@@ -15,8 +15,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: mutter\n"
|
"Project-Id-Version: mutter\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2015-03-05 00:23+0100\n"
|
"POT-Creation-Date: 2015-08-26 18:49+0200\n"
|
||||||
"PO-Revision-Date: 2015-03-05 00:24+0100\n"
|
"PO-Revision-Date: 2015-08-26 18:50+0200\n"
|
||||||
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
|
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
|
||||||
"Language-Team: Polish <gnomepl@aviary.pl>\n"
|
"Language-Team: Polish <gnomepl@aviary.pl>\n"
|
||||||
"Language: pl\n"
|
"Language: pl\n"
|
||||||
@@ -285,9 +285,9 @@ msgid ""
|
|||||||
"\"Windows key\" on PC hardware. It's expected that this binding either the "
|
"\"Windows key\" on PC hardware. It's expected that this binding either the "
|
||||||
"default or set to the empty string."
|
"default or set to the empty string."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ten klawisz inicjuje tryb \"overlay\", który jest połączeniem podglądu okien "
|
"Ten klawisz inicjuje tryb „overlay”, który jest połączeniem podglądu okien i "
|
||||||
"i systemu uruchamiania programów. Domyślnie jest przeznaczony do powiązania "
|
"systemu uruchamiania programów. Domyślnie jest przeznaczony do powiązania z "
|
||||||
"z klawiszem \"Windows\" na komputerach typu PC. Ustawienie tego powiązania "
|
"klawiszem „Windows” na komputerach typu PC. Ustawienie tego powiązania "
|
||||||
"powinno być domyślne lub puste."
|
"powinno być domyślne lub puste."
|
||||||
|
|
||||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:3
|
#: ../data/org.gnome.mutter.gschema.xml.in.h:3
|
||||||
@@ -300,9 +300,9 @@ msgid ""
|
|||||||
"attached to the titlebar of the parent window and are moved together with "
|
"attached to the titlebar of the parent window and are moved together with "
|
||||||
"the parent window."
|
"the parent window."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Jeśli wynosi \"true\", to modalne okna dialogowe pojawiają się dołączone do "
|
"Jeśli wynosi wartość „true”, to modalne okna dialogowe pojawiają się "
|
||||||
"paska tytułowego okna nadrzędnego zamiast posiadać oddzielne paski tytułowe "
|
"dołączone do paska tytułowego okna nadrzędnego zamiast posiadać oddzielne "
|
||||||
"i są przenoszone razem z nim."
|
"paski tytułowe i są przenoszone razem z nim."
|
||||||
|
|
||||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:5
|
#: ../data/org.gnome.mutter.gschema.xml.in.h:5
|
||||||
msgid "Enable edge tiling when dropping windows on screen edges"
|
msgid "Enable edge tiling when dropping windows on screen edges"
|
||||||
@@ -332,7 +332,7 @@ msgid ""
|
|||||||
"gnome.desktop.wm.preferences)."
|
"gnome.desktop.wm.preferences)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Określa, czy obszary robocze są zarządzane dynamicznie, czy istnieje "
|
"Określa, czy obszary robocze są zarządzane dynamicznie, czy istnieje "
|
||||||
"statyczna liczba obszarów (określona przez klucz \"num-workspaces\" w org."
|
"statyczna liczba obszarów (określona przez klucz „num-workspaces” w org."
|
||||||
"gnome.desktop.wm.preferences)."
|
"gnome.desktop.wm.preferences)."
|
||||||
|
|
||||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:9
|
#: ../data/org.gnome.mutter.gschema.xml.in.h:9
|
||||||
@@ -369,9 +369,9 @@ msgid ""
|
|||||||
"the focus will not be changed immediately when entering a window, but only "
|
"the focus will not be changed immediately when entering a window, but only "
|
||||||
"after the pointer stops moving."
|
"after the pointer stops moving."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Jeśli jest ustawione na wartość \"true\", a tryb aktywności to \"sloppy\" "
|
"Jeśli jest ustawione na wartość „true”, a tryb aktywności to „sloppy” lub "
|
||||||
"lub \"mouse\", to aktywność nie będzie zmieniana od razu po przejściu do "
|
"„mouse”, to aktywność nie będzie zmieniana od razu po przejściu do okna, ale "
|
||||||
"okna, ale dopiero po zatrzymaniu ruchu kursora."
|
"dopiero po zatrzymaniu ruchu kursora."
|
||||||
|
|
||||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:15
|
#: ../data/org.gnome.mutter.gschema.xml.in.h:15
|
||||||
msgid "Draggable border width"
|
msgid "Draggable border width"
|
||||||
@@ -409,7 +409,7 @@ msgid ""
|
|||||||
"When true, the new windows will always be put in the center of the active "
|
"When true, the new windows will always be put in the center of the active "
|
||||||
"screen of the monitor."
|
"screen of the monitor."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Jeśli wynosi \"true\", to nowe okna będą zawsze umieszczane na środku "
|
"Jeśli wynosi wartość „true”, to nowe okna będą zawsze umieszczane na środku "
|
||||||
"aktywnego ekranu monitora."
|
"aktywnego ekranu monitora."
|
||||||
|
|
||||||
#: ../data/org.gnome.mutter.gschema.xml.in.h:21
|
#: ../data/org.gnome.mutter.gschema.xml.in.h:21
|
||||||
@@ -468,22 +468,22 @@ msgstr "Przełączenie na 11. konsolę wirtualną"
|
|||||||
msgid "Switch to VT 12"
|
msgid "Switch to VT 12"
|
||||||
msgstr "Przełączenie na 12. konsolę wirtualną"
|
msgstr "Przełączenie na 12. konsolę wirtualną"
|
||||||
|
|
||||||
#: ../src/backends/meta-monitor-manager.c:364
|
#: ../src/backends/meta-monitor-manager.c:500
|
||||||
msgid "Built-in display"
|
msgid "Built-in display"
|
||||||
msgstr "Wbudowany ekran"
|
msgstr "Wbudowany ekran"
|
||||||
|
|
||||||
#: ../src/backends/meta-monitor-manager.c:391
|
#: ../src/backends/meta-monitor-manager.c:526
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "Nieznany"
|
msgstr "Nieznany"
|
||||||
|
|
||||||
#: ../src/backends/meta-monitor-manager.c:393
|
#: ../src/backends/meta-monitor-manager.c:528
|
||||||
msgid "Unknown Display"
|
msgid "Unknown Display"
|
||||||
msgstr "Nieznany ekran"
|
msgstr "Nieznany ekran"
|
||||||
|
|
||||||
#. TRANSLATORS: this is a monitor vendor name, followed by a
|
#. TRANSLATORS: this is a monitor vendor name, followed by a
|
||||||
#. * size in inches, like 'Dell 15"'
|
#. * size in inches, like 'Dell 15"'
|
||||||
#.
|
#.
|
||||||
#: ../src/backends/meta-monitor-manager.c:401
|
#: ../src/backends/meta-monitor-manager.c:536
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s %s"
|
msgid "%s %s"
|
||||||
msgstr "%s %s"
|
msgstr "%s %s"
|
||||||
@@ -496,7 +496,7 @@ msgid ""
|
|||||||
"Another compositing manager is already running on screen %i on display \"%s"
|
"Another compositing manager is already running on screen %i on display \"%s"
|
||||||
"\"."
|
"\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Inny menedżer składania jest już uruchomiony na podekranie %i ekranu \"%s\"."
|
"Inny menedżer składania jest już uruchomiony na podekranie %i ekranu „%s”."
|
||||||
|
|
||||||
#: ../src/core/bell.c:185
|
#: ../src/core/bell.c:185
|
||||||
msgid "Bell event"
|
msgid "Bell event"
|
||||||
@@ -505,7 +505,7 @@ msgstr "Zdarzenie sygnału dźwiękowego"
|
|||||||
#: ../src/core/delete.c:127
|
#: ../src/core/delete.c:127
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "“%s” is not responding."
|
msgid "“%s” is not responding."
|
||||||
msgstr "Okno \"%s\" nie odpowiada."
|
msgstr "Okno „%s” nie odpowiada."
|
||||||
|
|
||||||
#: ../src/core/delete.c:129
|
#: ../src/core/delete.c:129
|
||||||
msgid "Application is not responding."
|
msgid "Application is not responding."
|
||||||
@@ -525,11 +525,10 @@ msgstr "_Czekaj"
|
|||||||
msgid "_Force Quit"
|
msgid "_Force Quit"
|
||||||
msgstr "_Zakończ"
|
msgstr "_Zakończ"
|
||||||
|
|
||||||
#: ../src/core/display.c:562
|
#: ../src/core/display.c:563
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Failed to open X Window System display '%s'\n"
|
msgid "Failed to open X Window System display '%s'\n"
|
||||||
msgstr ""
|
msgstr "Otwarcie połączenia z ekranem „%s” systemu X Window się nie powiodło\n"
|
||||||
"Otwarcie połączenia z ekranem \"%s\" systemu X Window się nie powiodło\n"
|
|
||||||
|
|
||||||
#: ../src/core/main.c:176
|
#: ../src/core/main.c:176
|
||||||
msgid "Disable connection to session manager"
|
msgid "Disable connection to session manager"
|
||||||
@@ -573,7 +572,7 @@ msgid ""
|
|||||||
"PARTICULAR PURPOSE.\n"
|
"PARTICULAR PURPOSE.\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"mutter %s\n"
|
"mutter %s\n"
|
||||||
"Copyright (C) 2001-%d Havoc Pennington, Red Hat, Inc., oraz inni\n"
|
"Copyright (C) 2001—%d Havoc Pennington, Red Hat, Inc., oraz inni\n"
|
||||||
"Niniejszy program jest wolnym oprogramowaniem, aby poznać warunki, pod\n"
|
"Niniejszy program jest wolnym oprogramowaniem, aby poznać warunki, pod\n"
|
||||||
"jakimi dopuszczalne jest kopiowanie programu, zajrzyj do jego źródeł.\n"
|
"jakimi dopuszczalne jest kopiowanie programu, zajrzyj do jego źródeł.\n"
|
||||||
"Na program nie udziela się ŻADNYCH GWARANCJI, nawet domyślnej gwarancji\n"
|
"Na program nie udziela się ŻADNYCH GWARANCJI, nawet domyślnej gwarancji\n"
|
||||||
@@ -598,13 +597,13 @@ msgid ""
|
|||||||
"Display \"%s\" already has a window manager; try using the --replace option "
|
"Display \"%s\" already has a window manager; try using the --replace option "
|
||||||
"to replace the current window manager."
|
"to replace the current window manager."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Na ekranie \"%s\" działa już menedżer okien. Aby zastąpić działającego "
|
"Na ekranie „%s” działa już menedżer okien. Aby zastąpić działającego "
|
||||||
"menedżera okien, proszę spróbować użyć opcji --replace."
|
"menedżera okien, proszę spróbować użyć opcji --replace."
|
||||||
|
|
||||||
#: ../src/core/screen.c:607
|
#: ../src/core/screen.c:607
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Screen %d on display '%s' is invalid\n"
|
msgid "Screen %d on display '%s' is invalid\n"
|
||||||
msgstr "Podekran %d ekranu \"%s\" jest nieprawidłowy\n"
|
msgstr "Podekran %d ekranu „%s” jest nieprawidłowy\n"
|
||||||
|
|
||||||
#: ../src/core/util.c:118
|
#: ../src/core/util.c:118
|
||||||
msgid "Mutter was compiled without support for verbose mode\n"
|
msgid "Mutter was compiled without support for verbose mode\n"
|
||||||
@@ -616,7 +615,7 @@ msgid ""
|
|||||||
"These windows do not support "save current setup" and will have to "
|
"These windows do not support "save current setup" and will have to "
|
||||||
"be restarted manually next time you log in."
|
"be restarted manually next time you log in."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Te okna nie obsługują opcji zapisu obecnego stanu (\"save current setup\"), "
|
"Te okna nie obsługują opcji zapisu obecnego stanu („save current setup”), "
|
||||||
"więc przy następnym zalogowaniu będą musiały zostać uruchomione ręcznie."
|
"więc przy następnym zalogowaniu będą musiały zostać uruchomione ręcznie."
|
||||||
|
|
||||||
#: ../src/x11/window-props.c:549
|
#: ../src/x11/window-props.c:549
|
||||||
|
20
po/zh_TW.po
20
po/zh_TW.po
@@ -10,7 +10,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: metacity 3.3.4\n"
|
"Project-Id-Version: metacity 3.3.4\n"
|
||||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
|
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
|
||||||
"product=mutter&keywords=I18N+L10N&component=general\n"
|
"product=mutter&keywords=I18N+L10N&component=general\n"
|
||||||
"POT-Creation-Date: 2015-02-20 23:22+0000\n"
|
"POT-Creation-Date: 2015-07-21 10:52+0000\n"
|
||||||
"PO-Revision-Date: 2015-02-21 16:33+0800\n"
|
"PO-Revision-Date: 2015-02-21 16:33+0800\n"
|
||||||
"Last-Translator: Chao-Hsiung Liao <j_h_liau@yahoo.com.tw>\n"
|
"Last-Translator: Chao-Hsiung Liao <j_h_liau@yahoo.com.tw>\n"
|
||||||
"Language-Team: Chinese (Taiwan) <zh-l10n@lists.linux.org.tw>\n"
|
"Language-Team: Chinese (Taiwan) <zh-l10n@lists.linux.org.tw>\n"
|
||||||
@@ -439,22 +439,22 @@ msgstr "切換至 VT 11"
|
|||||||
msgid "Switch to VT 12"
|
msgid "Switch to VT 12"
|
||||||
msgstr "切換至 VT 12"
|
msgstr "切換至 VT 12"
|
||||||
|
|
||||||
#: ../src/backends/meta-monitor-manager.c:364
|
#: ../src/backends/meta-monitor-manager.c:500
|
||||||
msgid "Built-in display"
|
msgid "Built-in display"
|
||||||
msgstr "內建顯示"
|
msgstr "內建顯示"
|
||||||
|
|
||||||
#: ../src/backends/meta-monitor-manager.c:391
|
#: ../src/backends/meta-monitor-manager.c:526
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "不明"
|
msgstr "不明"
|
||||||
|
|
||||||
#: ../src/backends/meta-monitor-manager.c:393
|
#: ../src/backends/meta-monitor-manager.c:528
|
||||||
msgid "Unknown Display"
|
msgid "Unknown Display"
|
||||||
msgstr "不明的顯示器"
|
msgstr "不明的顯示器"
|
||||||
|
|
||||||
#. TRANSLATORS: this is a monitor vendor name, followed by a
|
#. TRANSLATORS: this is a monitor vendor name, followed by a
|
||||||
#. * size in inches, like 'Dell 15"'
|
#. * size in inches, like 'Dell 15"'
|
||||||
#.
|
#.
|
||||||
#: ../src/backends/meta-monitor-manager.c:401
|
#: ../src/backends/meta-monitor-manager.c:536
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s %s"
|
msgid "%s %s"
|
||||||
msgstr "%s %s"
|
msgstr "%s %s"
|
||||||
@@ -462,7 +462,7 @@ msgstr "%s %s"
|
|||||||
# FIXME: I'm still unclear about the meaning of XGetSelectionOwner -- Abel
|
# FIXME: I'm still unclear about the meaning of XGetSelectionOwner -- Abel
|
||||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||||
#. * we have no way to get it to exit
|
#. * we have no way to get it to exit
|
||||||
#: ../src/compositor/compositor.c:456
|
#: ../src/compositor/compositor.c:451
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Another compositing manager is already running on screen %i on display \"%s"
|
"Another compositing manager is already running on screen %i on display \"%s"
|
||||||
@@ -496,14 +496,14 @@ msgstr "等待(_W)"
|
|||||||
msgid "_Force Quit"
|
msgid "_Force Quit"
|
||||||
msgstr "強制結束(_F)"
|
msgstr "強制結束(_F)"
|
||||||
|
|
||||||
#: ../src/core/display.c:562
|
#: ../src/core/display.c:563
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Failed to open X Window System display '%s'\n"
|
msgid "Failed to open X Window System display '%s'\n"
|
||||||
msgstr "無法開啟 X Window 畫面‘%s’\n"
|
msgstr "無法開啟 X Window 畫面‘%s’\n"
|
||||||
|
|
||||||
#: ../src/core/main.c:176
|
#: ../src/core/main.c:176
|
||||||
msgid "Disable connection to session manager"
|
msgid "Disable connection to session manager"
|
||||||
msgstr "停用到作業階段管理程式的連線"
|
msgstr "停用到作業階段管理員的連線"
|
||||||
|
|
||||||
#: ../src/core/main.c:182
|
#: ../src/core/main.c:182
|
||||||
msgid "Replace the running window manager"
|
msgid "Replace the running window manager"
|
||||||
@@ -1053,9 +1053,9 @@ msgstr "%s(在 %s)"
|
|||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "\"%s\" found in configuration database is not a valid value for mouse "
|
#~ "\"%s\" found in configuration database is not a valid value for mouse "
|
||||||
#~ "button modifier\n"
|
#~ "button modifier\n"
|
||||||
#~ msgstr "組態資料庫中的“%s”設定值不是有效的滑鼠按鈕修改功能鍵\n"
|
#~ msgstr "設定資料庫中的“%s”設定值不是有效的滑鼠按鈕修改功能鍵\n"
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "\"%s\" found in configuration database is not a valid value for "
|
#~ "\"%s\" found in configuration database is not a valid value for "
|
||||||
#~ "keybinding \"%s\"\n"
|
#~ "keybinding \"%s\"\n"
|
||||||
#~ msgstr "組態資料庫中的“%s”不是按鍵組合“%s”的有效設定值\n"
|
#~ msgstr "設定資料庫中的“%s”不是按鍵組合“%s”的有效設定值\n"
|
||||||
|
@@ -45,6 +45,8 @@ mutter_built_sources = \
|
|||||||
|
|
||||||
if HAVE_WAYLAND
|
if HAVE_WAYLAND
|
||||||
mutter_built_sources += \
|
mutter_built_sources += \
|
||||||
|
pointer-gestures-protocol.c \
|
||||||
|
pointer-gestures-server-protocol.h \
|
||||||
gtk-shell-protocol.c \
|
gtk-shell-protocol.c \
|
||||||
gtk-shell-server-protocol.h \
|
gtk-shell-server-protocol.h \
|
||||||
xdg-shell-protocol.c \
|
xdg-shell-protocol.c \
|
||||||
@@ -53,6 +55,7 @@ mutter_built_sources += \
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
wayland_protocols = \
|
wayland_protocols = \
|
||||||
|
wayland/protocol/pointer-gestures.xml \
|
||||||
wayland/protocol/gtk-shell.xml \
|
wayland/protocol/gtk-shell.xml \
|
||||||
wayland/protocol/xdg-shell.xml \
|
wayland/protocol/xdg-shell.xml \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
@@ -65,7 +68,6 @@ libmutter_la_SOURCES = \
|
|||||||
backends/meta-barrier-private.h \
|
backends/meta-barrier-private.h \
|
||||||
backends/meta-cursor.c \
|
backends/meta-cursor.c \
|
||||||
backends/meta-cursor.h \
|
backends/meta-cursor.h \
|
||||||
backends/meta-cursor-private.h \
|
|
||||||
backends/meta-cursor-tracker.c \
|
backends/meta-cursor-tracker.c \
|
||||||
backends/meta-cursor-tracker-private.h \
|
backends/meta-cursor-tracker-private.h \
|
||||||
backends/meta-cursor-renderer.c \
|
backends/meta-cursor-renderer.c \
|
||||||
@@ -94,6 +96,8 @@ libmutter_la_SOURCES = \
|
|||||||
backends/x11/meta-barrier-x11.h \
|
backends/x11/meta-barrier-x11.h \
|
||||||
backends/x11/meta-cursor-renderer-x11.c \
|
backends/x11/meta-cursor-renderer-x11.c \
|
||||||
backends/x11/meta-cursor-renderer-x11.h \
|
backends/x11/meta-cursor-renderer-x11.h \
|
||||||
|
backends/x11/nested/meta-cursor-renderer-x11-nested.c \
|
||||||
|
backends/x11/nested/meta-cursor-renderer-x11-nested.h \
|
||||||
backends/x11/meta-idle-monitor-xsync.c \
|
backends/x11/meta-idle-monitor-xsync.c \
|
||||||
backends/x11/meta-idle-monitor-xsync.h \
|
backends/x11/meta-idle-monitor-xsync.h \
|
||||||
backends/x11/meta-input-settings-x11.c \
|
backends/x11/meta-input-settings-x11.c \
|
||||||
@@ -138,6 +142,8 @@ libmutter_la_SOURCES = \
|
|||||||
compositor/meta-surface-actor.h \
|
compositor/meta-surface-actor.h \
|
||||||
compositor/meta-surface-actor-x11.c \
|
compositor/meta-surface-actor-x11.c \
|
||||||
compositor/meta-surface-actor-x11.h \
|
compositor/meta-surface-actor-x11.h \
|
||||||
|
compositor/meta-sync-ring.c \
|
||||||
|
compositor/meta-sync-ring.h \
|
||||||
compositor/meta-texture-rectangle.c \
|
compositor/meta-texture-rectangle.c \
|
||||||
compositor/meta-texture-rectangle.h \
|
compositor/meta-texture-rectangle.h \
|
||||||
compositor/meta-texture-tower.c \
|
compositor/meta-texture-tower.c \
|
||||||
@@ -250,6 +256,12 @@ libmutter_la_SOURCES += \
|
|||||||
wayland/meta-wayland-data-device.c \
|
wayland/meta-wayland-data-device.c \
|
||||||
wayland/meta-wayland-data-device.h \
|
wayland/meta-wayland-data-device.h \
|
||||||
wayland/meta-wayland-data-device-private.h \
|
wayland/meta-wayland-data-device-private.h \
|
||||||
|
wayland/meta-wayland-pointer-gestures.c \
|
||||||
|
wayland/meta-wayland-pointer-gestures.h \
|
||||||
|
wayland/meta-wayland-pointer-gesture-swipe.c \
|
||||||
|
wayland/meta-wayland-pointer-gesture-swipe.h \
|
||||||
|
wayland/meta-wayland-pointer-gesture-pinch.c \
|
||||||
|
wayland/meta-wayland-pointer-gesture-pinch.h \
|
||||||
wayland/meta-wayland-keyboard.c \
|
wayland/meta-wayland-keyboard.c \
|
||||||
wayland/meta-wayland-keyboard.h \
|
wayland/meta-wayland-keyboard.h \
|
||||||
wayland/meta-wayland-pointer.c \
|
wayland/meta-wayland-pointer.c \
|
||||||
|
@@ -1,66 +0,0 @@
|
|||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2013 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef META_CURSOR_PRIVATE_H
|
|
||||||
#define META_CURSOR_PRIVATE_H
|
|
||||||
|
|
||||||
#include "meta-cursor.h"
|
|
||||||
|
|
||||||
#include <X11/Xcursor/Xcursor.h>
|
|
||||||
#include <cogl/cogl.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
#include <gbm.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
CoglTexture2D *texture;
|
|
||||||
int hot_x, hot_y;
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
struct gbm_bo *bo;
|
|
||||||
#endif
|
|
||||||
} MetaCursorImage;
|
|
||||||
|
|
||||||
struct _MetaCursorReference {
|
|
||||||
int ref_count;
|
|
||||||
|
|
||||||
int current_frame;
|
|
||||||
XcursorImages *xcursor_images;
|
|
||||||
MetaCursor cursor;
|
|
||||||
MetaCursorImage image;
|
|
||||||
};
|
|
||||||
|
|
||||||
CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
|
|
||||||
int *hot_x,
|
|
||||||
int *hot_y);
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
|
||||||
int *hot_x,
|
|
||||||
int *hot_y);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gboolean meta_cursor_reference_is_animated (MetaCursorReference *self);
|
|
||||||
void meta_cursor_reference_tick_frame (MetaCursorReference *self);
|
|
||||||
guint meta_cursor_reference_get_current_frame_time (MetaCursorReference *self);
|
|
||||||
|
|
||||||
#endif /* META_CURSOR_PRIVATE_H */
|
|
@@ -25,7 +25,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "meta-cursor-renderer.h"
|
#include "meta-cursor-renderer.h"
|
||||||
#include "meta-cursor-private.h"
|
|
||||||
|
|
||||||
#include <meta/meta-backend.h>
|
#include <meta/meta-backend.h>
|
||||||
#include <meta/util.h>
|
#include <meta/util.h>
|
||||||
@@ -38,9 +37,8 @@
|
|||||||
struct _MetaCursorRendererPrivate
|
struct _MetaCursorRendererPrivate
|
||||||
{
|
{
|
||||||
int current_x, current_y;
|
int current_x, current_y;
|
||||||
MetaRectangle current_rect;
|
|
||||||
|
|
||||||
MetaCursorReference *displayed_cursor;
|
MetaCursorSprite *displayed_cursor;
|
||||||
gboolean handled_by_backend;
|
gboolean handled_by_backend;
|
||||||
};
|
};
|
||||||
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
|
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
|
||||||
@@ -48,27 +46,33 @@ typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
|
|||||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
queue_redraw (MetaCursorRenderer *renderer)
|
queue_redraw (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
||||||
MetaBackend *backend = meta_get_backend ();
|
MetaBackend *backend = meta_get_backend ();
|
||||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||||
CoglTexture *texture;
|
CoglTexture *texture;
|
||||||
|
MetaRectangle rect = { 0 };
|
||||||
|
|
||||||
|
if (cursor_sprite)
|
||||||
|
rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
|
||||||
|
|
||||||
/* During early initialization, we can have no stage */
|
/* During early initialization, we can have no stage */
|
||||||
if (!stage)
|
if (!stage)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (priv->displayed_cursor && !priv->handled_by_backend)
|
if (cursor_sprite && !priv->handled_by_backend)
|
||||||
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, NULL, NULL);
|
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
||||||
else
|
else
|
||||||
texture = NULL;
|
texture = NULL;
|
||||||
|
|
||||||
meta_stage_set_cursor (META_STAGE (stage), texture, &priv->current_rect);
|
meta_stage_set_cursor (META_STAGE (stage), texture, &rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer)
|
meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -84,34 +88,50 @@ meta_cursor_renderer_init (MetaCursorRenderer *renderer)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaRectangle
|
||||||
|
meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
MetaCursorRendererPrivate *priv =
|
||||||
|
meta_cursor_renderer_get_instance_private (renderer);
|
||||||
|
CoglTexture *texture;
|
||||||
|
int hot_x, hot_y;
|
||||||
|
int width, height;
|
||||||
|
float texture_scale;
|
||||||
|
|
||||||
|
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
||||||
|
if (!texture)
|
||||||
|
return (MetaRectangle) { 0 };
|
||||||
|
|
||||||
|
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
|
||||||
|
texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
|
||||||
|
width = cogl_texture_get_width (texture);
|
||||||
|
height = cogl_texture_get_height (texture);
|
||||||
|
|
||||||
|
return (MetaRectangle) {
|
||||||
|
.x = (int)roundf (priv->current_x - (hot_x * texture_scale)),
|
||||||
|
.y = (int)roundf (priv->current_y - (hot_y * texture_scale)),
|
||||||
|
.width = (int)roundf (width * texture_scale),
|
||||||
|
.height = (int)roundf (height * texture_scale),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_cursor (MetaCursorRenderer *renderer)
|
update_cursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
||||||
gboolean handled_by_backend;
|
gboolean handled_by_backend;
|
||||||
gboolean should_redraw = FALSE;
|
gboolean should_redraw = FALSE;
|
||||||
|
|
||||||
if (priv->displayed_cursor)
|
if (cursor_sprite)
|
||||||
{
|
meta_cursor_sprite_prepare_at (cursor_sprite,
|
||||||
CoglTexture *texture;
|
priv->current_x,
|
||||||
int hot_x, hot_y;
|
priv->current_y);
|
||||||
|
|
||||||
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, &hot_x, &hot_y);
|
handled_by_backend =
|
||||||
|
META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer,
|
||||||
priv->current_rect.x = priv->current_x - hot_x;
|
cursor_sprite);
|
||||||
priv->current_rect.y = priv->current_y - hot_y;
|
|
||||||
priv->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
|
|
||||||
priv->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
priv->current_rect.x = 0;
|
|
||||||
priv->current_rect.y = 0;
|
|
||||||
priv->current_rect.width = 0;
|
|
||||||
priv->current_rect.height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer);
|
|
||||||
if (handled_by_backend != priv->handled_by_backend)
|
if (handled_by_backend != priv->handled_by_backend)
|
||||||
{
|
{
|
||||||
priv->handled_by_backend = handled_by_backend;
|
priv->handled_by_backend = handled_by_backend;
|
||||||
@@ -122,7 +142,7 @@ update_cursor (MetaCursorRenderer *renderer)
|
|||||||
should_redraw = TRUE;
|
should_redraw = TRUE;
|
||||||
|
|
||||||
if (should_redraw)
|
if (should_redraw)
|
||||||
queue_redraw (renderer);
|
queue_redraw (renderer, cursor_sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCursorRenderer *
|
MetaCursorRenderer *
|
||||||
@@ -132,23 +152,25 @@ meta_cursor_renderer_new (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
|
meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
|
||||||
MetaCursorReference *cursor)
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
||||||
|
|
||||||
if (priv->displayed_cursor == cursor)
|
if (priv->displayed_cursor == cursor_sprite)
|
||||||
return;
|
return;
|
||||||
|
priv->displayed_cursor = cursor_sprite;
|
||||||
|
|
||||||
priv->displayed_cursor = cursor;
|
update_cursor (renderer, cursor_sprite);
|
||||||
update_cursor (renderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
|
meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
|
||||||
{
|
{
|
||||||
update_cursor (renderer);
|
MetaCursorRendererPrivate *priv =
|
||||||
queue_redraw (renderer);
|
meta_cursor_renderer_get_instance_private (renderer);
|
||||||
|
|
||||||
|
update_cursor (renderer, priv->displayed_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -162,10 +184,10 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
|
|||||||
priv->current_x = x;
|
priv->current_x = x;
|
||||||
priv->current_y = y;
|
priv->current_y = y;
|
||||||
|
|
||||||
update_cursor (renderer);
|
update_cursor (renderer, priv->displayed_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCursorReference *
|
MetaCursorSprite *
|
||||||
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
|
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
|
||||||
{
|
{
|
||||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
||||||
@@ -173,10 +195,27 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
|
|||||||
return priv->displayed_cursor;
|
return priv->displayed_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MetaRectangle *
|
#ifdef HAVE_WAYLAND
|
||||||
meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
|
void
|
||||||
|
meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
struct wl_resource *buffer)
|
||||||
{
|
{
|
||||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
|
||||||
|
|
||||||
return &priv->current_rect;
|
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
|
||||||
|
|
||||||
|
if (renderer_class->realize_cursor_from_wl_buffer)
|
||||||
|
renderer_class->realize_cursor_from_wl_buffer (renderer, cursor_sprite, buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
XcursorImage *xc_image)
|
||||||
|
{
|
||||||
|
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
|
||||||
|
|
||||||
|
if (renderer_class->realize_cursor_from_xcursor)
|
||||||
|
renderer_class->realize_cursor_from_xcursor (renderer, cursor_sprite, xc_image);
|
||||||
}
|
}
|
||||||
|
@@ -26,44 +26,58 @@
|
|||||||
#define META_CURSOR_RENDERER_H
|
#define META_CURSOR_RENDERER_H
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include <X11/Xcursor/Xcursor.h>
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <meta/screen.h>
|
#include <meta/screen.h>
|
||||||
#include "meta-cursor.h"
|
#include "meta-cursor.h"
|
||||||
|
|
||||||
#define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
|
#define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
|
||||||
#define META_CURSOR_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_RENDERER, MetaCursorRenderer))
|
G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer,
|
||||||
#define META_CURSOR_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_RENDERER, MetaCursorRendererClass))
|
META, CURSOR_RENDERER, GObject);
|
||||||
#define META_IS_CURSOR_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_RENDERER))
|
|
||||||
#define META_IS_CURSOR_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_RENDERER))
|
|
||||||
#define META_CURSOR_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_RENDERER, MetaCursorRendererClass))
|
|
||||||
|
|
||||||
typedef struct _MetaCursorRenderer MetaCursorRenderer;
|
|
||||||
typedef struct _MetaCursorRendererClass MetaCursorRendererClass;
|
|
||||||
|
|
||||||
struct _MetaCursorRenderer
|
|
||||||
{
|
|
||||||
GObject parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _MetaCursorRendererClass
|
struct _MetaCursorRendererClass
|
||||||
{
|
{
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
gboolean (* update_cursor) (MetaCursorRenderer *renderer);
|
gboolean (* update_cursor) (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite);
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
void (* realize_cursor_from_wl_buffer) (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
struct wl_resource *buffer);
|
||||||
|
#endif
|
||||||
|
void (* realize_cursor_from_xcursor) (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
XcursorImage *xc_image);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType meta_cursor_renderer_get_type (void) G_GNUC_CONST;
|
GType meta_cursor_renderer_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
MetaCursorRenderer * meta_cursor_renderer_new (void);
|
MetaCursorRenderer * meta_cursor_renderer_new (void);
|
||||||
|
|
||||||
void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
|
void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
|
||||||
MetaCursorReference *cursor);
|
MetaCursorSprite *cursor_sprite);
|
||||||
|
|
||||||
void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
|
void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
|
||||||
int x, int y);
|
int x, int y);
|
||||||
void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
|
void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
|
||||||
|
|
||||||
MetaCursorReference * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
|
MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
|
||||||
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
|
|
||||||
|
MetaRectangle meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite);
|
||||||
|
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
void meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
struct wl_resource *buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
XcursorImage *xc_image);
|
||||||
|
|
||||||
#endif /* META_CURSOR_RENDERER_H */
|
#endif /* META_CURSOR_RENDERER_H */
|
||||||
|
@@ -34,7 +34,7 @@ struct _MetaCursorTracker {
|
|||||||
|
|
||||||
gboolean is_showing;
|
gboolean is_showing;
|
||||||
|
|
||||||
MetaCursorReference *displayed_cursor;
|
MetaCursorSprite *displayed_cursor;
|
||||||
|
|
||||||
/* Wayland clients can set a NULL buffer as their cursor
|
/* Wayland clients can set a NULL buffer as their cursor
|
||||||
* explicitly, which means that we shouldn't display anything.
|
* explicitly, which means that we shouldn't display anything.
|
||||||
@@ -42,12 +42,12 @@ struct _MetaCursorTracker {
|
|||||||
* determine an unset window cursor; we need an extra boolean.
|
* determine an unset window cursor; we need an extra boolean.
|
||||||
*/
|
*/
|
||||||
gboolean has_window_cursor;
|
gboolean has_window_cursor;
|
||||||
MetaCursorReference *window_cursor;
|
MetaCursorSprite *window_cursor;
|
||||||
|
|
||||||
MetaCursorReference *root_cursor;
|
MetaCursorSprite *root_cursor;
|
||||||
|
|
||||||
/* The cursor from the X11 server. */
|
/* The cursor from the X11 server. */
|
||||||
MetaCursorReference *xfixes_cursor;
|
MetaCursorSprite *xfixes_cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaCursorTrackerClass {
|
struct _MetaCursorTrackerClass {
|
||||||
@@ -57,16 +57,16 @@ struct _MetaCursorTrackerClass {
|
|||||||
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||||
XEvent *xevent);
|
XEvent *xevent);
|
||||||
|
|
||||||
void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
|
void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
|
||||||
MetaCursorReference *cursor);
|
MetaCursorSprite *cursor_sprite);
|
||||||
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
|
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
|
||||||
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||||
MetaCursorReference *cursor);
|
MetaCursorSprite *cursor_sprite);
|
||||||
|
|
||||||
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
|
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
|
||||||
int new_x,
|
int new_x,
|
||||||
int new_y);
|
int new_y);
|
||||||
|
|
||||||
MetaCursorReference * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);
|
MetaCursorSprite * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -43,7 +43,6 @@
|
|||||||
#include <X11/extensions/Xfixes.h>
|
#include <X11/extensions/Xfixes.h>
|
||||||
|
|
||||||
#include "meta-backend-private.h"
|
#include "meta-backend-private.h"
|
||||||
#include "meta-cursor-private.h"
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
|
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
|
||||||
|
|
||||||
@@ -54,7 +53,7 @@ enum {
|
|||||||
|
|
||||||
static guint signals[LAST_SIGNAL];
|
static guint signals[LAST_SIGNAL];
|
||||||
|
|
||||||
static MetaCursorReference *
|
static MetaCursorSprite *
|
||||||
get_displayed_cursor (MetaCursorTracker *tracker)
|
get_displayed_cursor (MetaCursorTracker *tracker)
|
||||||
{
|
{
|
||||||
MetaDisplay *display = meta_get_display ();
|
MetaDisplay *display = meta_get_display ();
|
||||||
@@ -80,14 +79,14 @@ update_displayed_cursor (MetaCursorTracker *tracker)
|
|||||||
static void
|
static void
|
||||||
sync_cursor (MetaCursorTracker *tracker)
|
sync_cursor (MetaCursorTracker *tracker)
|
||||||
{
|
{
|
||||||
MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker);
|
MetaCursorSprite *displayed_cursor = get_displayed_cursor (tracker);
|
||||||
|
|
||||||
if (tracker->displayed_cursor == displayed_cursor)
|
if (tracker->displayed_cursor == displayed_cursor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref);
|
g_clear_object (&tracker->displayed_cursor);
|
||||||
if (displayed_cursor)
|
if (displayed_cursor)
|
||||||
tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor);
|
tracker->displayed_cursor = g_object_ref (displayed_cursor);
|
||||||
|
|
||||||
update_displayed_cursor (tracker);
|
update_displayed_cursor (tracker);
|
||||||
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
||||||
@@ -108,9 +107,9 @@ meta_cursor_tracker_finalize (GObject *object)
|
|||||||
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
|
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
|
||||||
|
|
||||||
if (self->displayed_cursor)
|
if (self->displayed_cursor)
|
||||||
meta_cursor_reference_unref (self->displayed_cursor);
|
g_object_unref (self->displayed_cursor);
|
||||||
if (self->root_cursor)
|
if (self->root_cursor)
|
||||||
meta_cursor_reference_unref (self->root_cursor);
|
g_object_unref (self->root_cursor);
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@@ -156,13 +155,13 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_window_cursor (MetaCursorTracker *tracker,
|
set_window_cursor (MetaCursorTracker *tracker,
|
||||||
gboolean has_cursor,
|
gboolean has_cursor,
|
||||||
MetaCursorReference *cursor)
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref);
|
g_clear_object (&tracker->window_cursor);
|
||||||
if (cursor)
|
if (cursor_sprite)
|
||||||
tracker->window_cursor = meta_cursor_reference_ref (cursor);
|
tracker->window_cursor = g_object_ref (cursor_sprite);
|
||||||
tracker->has_window_cursor = has_cursor;
|
tracker->has_window_cursor = has_cursor;
|
||||||
sync_cursor (tracker);
|
sync_cursor (tracker);
|
||||||
}
|
}
|
||||||
@@ -184,28 +183,12 @@ meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
|||||||
if (notify_event->subtype != XFixesDisplayCursorNotify)
|
if (notify_event->subtype != XFixesDisplayCursorNotify)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
g_clear_pointer (&tracker->xfixes_cursor, meta_cursor_reference_unref);
|
g_clear_object (&tracker->xfixes_cursor);
|
||||||
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MetaCursorReference *
|
|
||||||
meta_cursor_reference_take_texture (CoglTexture2D *texture,
|
|
||||||
int hot_x,
|
|
||||||
int hot_y)
|
|
||||||
{
|
|
||||||
MetaCursorReference *self;
|
|
||||||
|
|
||||||
self = g_slice_new0 (MetaCursorReference);
|
|
||||||
self->ref_count = 1;
|
|
||||||
self->image.texture = texture;
|
|
||||||
self->image.hot_x = hot_x;
|
|
||||||
self->image.hot_y = hot_y;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
||||||
{
|
{
|
||||||
@@ -263,10 +246,13 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
|||||||
|
|
||||||
if (sprite != NULL)
|
if (sprite != NULL)
|
||||||
{
|
{
|
||||||
MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite,
|
MetaCursorSprite *cursor_sprite = meta_cursor_sprite_new ();
|
||||||
cursor_image->xhot,
|
meta_cursor_sprite_set_texture (cursor_sprite,
|
||||||
cursor_image->yhot);
|
sprite,
|
||||||
tracker->xfixes_cursor = cursor;
|
cursor_image->xhot,
|
||||||
|
cursor_image->yhot);
|
||||||
|
cogl_object_unref (sprite);
|
||||||
|
tracker->xfixes_cursor = cursor_sprite;
|
||||||
}
|
}
|
||||||
XFree (cursor_image);
|
XFree (cursor_image);
|
||||||
}
|
}
|
||||||
@@ -279,22 +265,22 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
|||||||
CoglTexture *
|
CoglTexture *
|
||||||
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
|
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
|
||||||
{
|
{
|
||||||
MetaCursorReference *cursor;
|
MetaCursorSprite *cursor_sprite;
|
||||||
|
|
||||||
g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
|
g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
|
||||||
|
|
||||||
if (meta_is_wayland_compositor ())
|
if (meta_is_wayland_compositor ())
|
||||||
{
|
{
|
||||||
cursor = tracker->displayed_cursor;
|
cursor_sprite = tracker->displayed_cursor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ensure_xfixes_cursor (tracker);
|
ensure_xfixes_cursor (tracker);
|
||||||
cursor = tracker->xfixes_cursor;
|
cursor_sprite = tracker->xfixes_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor)
|
if (cursor_sprite)
|
||||||
return meta_cursor_reference_get_cogl_texture (cursor, NULL, NULL);
|
return meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -311,22 +297,22 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
|||||||
int *x,
|
int *x,
|
||||||
int *y)
|
int *y)
|
||||||
{
|
{
|
||||||
MetaCursorReference *cursor;
|
MetaCursorSprite *cursor_sprite;
|
||||||
|
|
||||||
g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
|
g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
|
||||||
|
|
||||||
if (meta_is_wayland_compositor ())
|
if (meta_is_wayland_compositor ())
|
||||||
{
|
{
|
||||||
cursor = tracker->displayed_cursor;
|
cursor_sprite = tracker->displayed_cursor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ensure_xfixes_cursor (tracker);
|
ensure_xfixes_cursor (tracker);
|
||||||
cursor = tracker->xfixes_cursor;
|
cursor_sprite = tracker->xfixes_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor)
|
if (cursor_sprite)
|
||||||
meta_cursor_reference_get_cogl_texture (cursor, x, y);
|
meta_cursor_sprite_get_hotspot (cursor_sprite, x, y);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (x)
|
if (x)
|
||||||
@@ -337,10 +323,10 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
|
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
|
||||||
MetaCursorReference *cursor)
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
set_window_cursor (tracker, TRUE, cursor);
|
set_window_cursor (tracker, TRUE, cursor_sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -350,12 +336,12 @@ meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||||
MetaCursorReference *cursor)
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
|
g_clear_object (&tracker->root_cursor);
|
||||||
if (cursor)
|
if (cursor_sprite)
|
||||||
tracker->root_cursor = meta_cursor_reference_ref (cursor);
|
tracker->root_cursor = g_object_ref (cursor_sprite);
|
||||||
|
|
||||||
sync_cursor (tracker);
|
sync_cursor (tracker);
|
||||||
}
|
}
|
||||||
@@ -438,7 +424,7 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
|
|||||||
sync_cursor (tracker);
|
sync_cursor (tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCursorReference *
|
MetaCursorSprite *
|
||||||
meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker)
|
meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker)
|
||||||
{
|
{
|
||||||
return tracker->displayed_cursor;
|
return tracker->displayed_cursor;
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "meta-cursor-private.h"
|
#include "meta-cursor.h"
|
||||||
|
|
||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
|
|
||||||
@@ -29,58 +29,40 @@
|
|||||||
#include "screen-private.h"
|
#include "screen-private.h"
|
||||||
#include "meta-backend-private.h"
|
#include "meta-backend-private.h"
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
#include "backends/native/meta-cursor-renderer-native.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <X11/cursorfont.h>
|
#include <X11/cursorfont.h>
|
||||||
#include <X11/extensions/Xfixes.h>
|
#include <X11/extensions/Xfixes.h>
|
||||||
#include <X11/Xcursor/Xcursor.h>
|
#include <X11/Xcursor/Xcursor.h>
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
enum {
|
||||||
#include <cogl/cogl-wayland-server.h>
|
PREPARE_AT,
|
||||||
#endif
|
|
||||||
|
|
||||||
MetaCursorReference *
|
LAST_SIGNAL
|
||||||
meta_cursor_reference_ref (MetaCursorReference *self)
|
};
|
||||||
|
|
||||||
|
static guint signals[LAST_SIGNAL];
|
||||||
|
|
||||||
|
struct _MetaCursorSprite
|
||||||
{
|
{
|
||||||
g_assert (self->ref_count > 0);
|
GObject parent;
|
||||||
self->ref_count++;
|
|
||||||
|
|
||||||
return self;
|
MetaCursor cursor;
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
CoglTexture2D *texture;
|
||||||
meta_cursor_image_free (MetaCursorImage *image)
|
float texture_scale;
|
||||||
{
|
int hot_x, hot_y;
|
||||||
if (image->texture)
|
|
||||||
cogl_object_unref (image->texture);
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
int current_frame;
|
||||||
if (image->bo)
|
XcursorImages *xcursor_images;
|
||||||
gbm_bo_destroy (image->bo);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
int theme_scale;
|
||||||
meta_cursor_reference_free (MetaCursorReference *self)
|
gboolean theme_dirty;
|
||||||
{
|
};
|
||||||
if (self->xcursor_images)
|
|
||||||
XcursorImagesDestroy (self->xcursor_images);
|
|
||||||
meta_cursor_image_free (&self->image);
|
|
||||||
g_slice_free (MetaCursorReference, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
GType meta_cursor_sprite_get_type (void) G_GNUC_CONST;
|
||||||
meta_cursor_reference_unref (MetaCursorReference *self)
|
|
||||||
{
|
|
||||||
self->ref_count--;
|
|
||||||
|
|
||||||
if (self->ref_count == 0)
|
G_DEFINE_TYPE (MetaCursorSprite, meta_cursor_sprite, G_TYPE_OBJECT)
|
||||||
meta_cursor_reference_free (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
translate_meta_cursor (MetaCursor cursor)
|
translate_meta_cursor (MetaCursor cursor)
|
||||||
@@ -138,92 +120,26 @@ meta_cursor_create_x_cursor (Display *xdisplay,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static XcursorImages *
|
static XcursorImages *
|
||||||
load_cursor_on_client (MetaCursor cursor)
|
load_cursor_on_client (MetaCursor cursor, int scale)
|
||||||
{
|
{
|
||||||
return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
|
return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
|
||||||
meta_prefs_get_cursor_theme (),
|
meta_prefs_get_cursor_theme (),
|
||||||
meta_prefs_get_cursor_size ());
|
meta_prefs_get_cursor_size () * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
static void
|
static void
|
||||||
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
|
meta_cursor_sprite_load_from_xcursor_image (MetaCursorSprite *self,
|
||||||
|
XcursorImage *xc_image)
|
||||||
{
|
{
|
||||||
MetaBackend *meta_backend = meta_get_backend ();
|
MetaBackend *meta_backend = meta_get_backend ();
|
||||||
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
|
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
|
||||||
|
|
||||||
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
|
|
||||||
{
|
|
||||||
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
static void
|
|
||||||
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
|
|
||||||
MetaCursorImage *image,
|
|
||||||
uint8_t *pixels,
|
|
||||||
uint width,
|
|
||||||
uint height,
|
|
||||||
int rowstride,
|
|
||||||
uint32_t gbm_format)
|
|
||||||
{
|
|
||||||
uint64_t cursor_width, cursor_height;
|
|
||||||
get_hardware_cursor_size (&cursor_width, &cursor_height);
|
|
||||||
|
|
||||||
if (width > cursor_width || height > cursor_height)
|
|
||||||
{
|
|
||||||
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
|
|
||||||
(unsigned int)cursor_width, (unsigned int)cursor_height);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gbm_device_is_format_supported (gbm, gbm_format,
|
|
||||||
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
|
|
||||||
{
|
|
||||||
uint8_t buf[4 * cursor_width * cursor_height];
|
|
||||||
uint i;
|
|
||||||
|
|
||||||
image->bo = gbm_bo_create (gbm, cursor_width, cursor_height,
|
|
||||||
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
|
||||||
|
|
||||||
memset (buf, 0, sizeof(buf));
|
|
||||||
for (i = 0; i < height; i++)
|
|
||||||
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
|
|
||||||
|
|
||||||
gbm_bo_write (image->bo, buf, cursor_width * cursor_height * 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
static struct gbm_device *
|
|
||||||
get_gbm_device (void)
|
|
||||||
{
|
|
||||||
MetaBackend *meta_backend = meta_get_backend ();
|
|
||||||
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
|
|
||||||
|
|
||||||
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
|
|
||||||
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
|
|
||||||
XcursorImage *xc_image)
|
|
||||||
{
|
|
||||||
uint width, height, rowstride;
|
uint width, height, rowstride;
|
||||||
CoglPixelFormat cogl_format;
|
CoglPixelFormat cogl_format;
|
||||||
ClutterBackend *clutter_backend;
|
ClutterBackend *clutter_backend;
|
||||||
CoglContext *cogl_context;
|
CoglContext *cogl_context;
|
||||||
|
CoglTexture *texture;
|
||||||
|
|
||||||
|
g_assert (self->texture == NULL);
|
||||||
|
|
||||||
width = xc_image->width;
|
width = xc_image->width;
|
||||||
height = xc_image->height;
|
height = xc_image->height;
|
||||||
@@ -235,41 +151,33 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
|
|||||||
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
|
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
image->hot_x = xc_image->xhot;
|
|
||||||
image->hot_y = xc_image->yhot;
|
|
||||||
|
|
||||||
clutter_backend = clutter_get_default_backend ();
|
clutter_backend = clutter_get_default_backend ();
|
||||||
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
||||||
image->texture = cogl_texture_2d_new_from_data (cogl_context,
|
texture = cogl_texture_2d_new_from_data (cogl_context,
|
||||||
width, height,
|
width, height,
|
||||||
cogl_format,
|
cogl_format,
|
||||||
rowstride,
|
rowstride,
|
||||||
(uint8_t *) xc_image->pixels,
|
(uint8_t *) xc_image->pixels,
|
||||||
NULL);
|
NULL);
|
||||||
|
meta_cursor_sprite_set_texture (self, texture,
|
||||||
|
xc_image->xhot, xc_image->yhot);
|
||||||
|
cogl_object_unref (texture);
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
meta_cursor_renderer_realize_cursor_from_xcursor (renderer, self, xc_image);
|
||||||
struct gbm_device *gbm = get_gbm_device ();
|
|
||||||
if (gbm)
|
|
||||||
meta_cursor_image_load_gbm_buffer (gbm,
|
|
||||||
image,
|
|
||||||
(uint8_t *) xc_image->pixels,
|
|
||||||
width, height, rowstride,
|
|
||||||
GBM_FORMAT_ARGB8888);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static XcursorImage *
|
static XcursorImage *
|
||||||
meta_cursor_reference_get_current_frame_image (MetaCursorReference *self)
|
meta_cursor_sprite_get_current_frame_image (MetaCursorSprite *self)
|
||||||
{
|
{
|
||||||
return self->xcursor_images->images[self->current_frame];
|
return self->xcursor_images->images[self->current_frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_cursor_reference_tick_frame (MetaCursorReference *self)
|
meta_cursor_sprite_tick_frame (MetaCursorSprite *self)
|
||||||
{
|
{
|
||||||
XcursorImage *image;
|
XcursorImage *image;
|
||||||
|
|
||||||
if (!meta_cursor_reference_is_animated (self))
|
if (!meta_cursor_sprite_is_animated (self))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self->current_frame++;
|
self->current_frame++;
|
||||||
@@ -277,198 +185,176 @@ meta_cursor_reference_tick_frame (MetaCursorReference *self)
|
|||||||
if (self->current_frame >= self->xcursor_images->nimage)
|
if (self->current_frame >= self->xcursor_images->nimage)
|
||||||
self->current_frame = 0;
|
self->current_frame = 0;
|
||||||
|
|
||||||
meta_cursor_image_free (&self->image);
|
image = meta_cursor_sprite_get_current_frame_image (self);
|
||||||
image = meta_cursor_reference_get_current_frame_image (self);
|
|
||||||
meta_cursor_image_load_from_xcursor_image (&self->image, image);
|
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||||
|
meta_cursor_sprite_load_from_xcursor_image (self, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
meta_cursor_reference_get_current_frame_time (MetaCursorReference *self)
|
meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *self)
|
||||||
{
|
{
|
||||||
if (!meta_cursor_reference_is_animated (self))
|
if (!meta_cursor_sprite_is_animated (self))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return self->xcursor_images->images[self->current_frame]->delay;
|
return self->xcursor_images->images[self->current_frame]->delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
meta_cursor_reference_is_animated (MetaCursorReference *self)
|
meta_cursor_sprite_is_animated (MetaCursorSprite *self)
|
||||||
{
|
{
|
||||||
return (self->xcursor_images &&
|
return (self->xcursor_images &&
|
||||||
self->xcursor_images->nimage > 1);
|
self->xcursor_images->nimage > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaCursorSprite *
|
||||||
|
meta_cursor_sprite_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
load_cursor_image (MetaCursorReference *cursor)
|
meta_cursor_sprite_load_from_theme (MetaCursorSprite *self)
|
||||||
{
|
{
|
||||||
XcursorImage *image;
|
XcursorImage *image;
|
||||||
|
|
||||||
/* Either cursors are loaded from X cursors or buffers. Since
|
g_assert (self->cursor != META_CURSOR_NONE);
|
||||||
* buffers are converted over immediately, we can make sure to
|
|
||||||
* load this directly. */
|
|
||||||
g_assert (cursor->cursor != META_CURSOR_NONE);
|
|
||||||
|
|
||||||
if (!cursor->xcursor_images)
|
/* We might be reloading with a different scale. If so clear the old data. */
|
||||||
|
if (self->xcursor_images)
|
||||||
{
|
{
|
||||||
cursor->current_frame = 0;
|
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||||
cursor->xcursor_images = load_cursor_on_client (cursor->cursor);
|
XcursorImagesDestroy (self->xcursor_images);
|
||||||
if (!cursor->xcursor_images)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
image = meta_cursor_reference_get_current_frame_image (cursor);
|
self->current_frame = 0;
|
||||||
meta_cursor_image_load_from_xcursor_image (&cursor->image, image);
|
self->xcursor_images = load_cursor_on_client (self->cursor,
|
||||||
|
self->theme_scale);
|
||||||
|
if (!self->xcursor_images)
|
||||||
|
meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
|
||||||
|
|
||||||
|
image = meta_cursor_sprite_get_current_frame_image (self);
|
||||||
|
meta_cursor_sprite_load_from_xcursor_image (self, image);
|
||||||
|
|
||||||
|
self->theme_dirty = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCursorReference *
|
MetaCursorSprite *
|
||||||
meta_cursor_reference_from_theme (MetaCursor cursor)
|
meta_cursor_sprite_from_theme (MetaCursor cursor)
|
||||||
{
|
{
|
||||||
MetaCursorReference *self = g_slice_new0 (MetaCursorReference);
|
MetaCursorSprite *self;
|
||||||
self->ref_count = 1;
|
|
||||||
|
self = meta_cursor_sprite_new ();
|
||||||
|
|
||||||
self->cursor = cursor;
|
self->cursor = cursor;
|
||||||
return self;
|
self->theme_dirty = TRUE;
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
|
||||||
static void
|
|
||||||
meta_cursor_image_load_from_buffer (MetaCursorImage *image,
|
|
||||||
struct wl_resource *buffer,
|
|
||||||
int hot_x,
|
|
||||||
int hot_y)
|
|
||||||
{
|
|
||||||
ClutterBackend *backend;
|
|
||||||
CoglContext *cogl_context;
|
|
||||||
|
|
||||||
image->hot_x = hot_x;
|
|
||||||
image->hot_y = hot_y;
|
|
||||||
|
|
||||||
backend = clutter_get_default_backend ();
|
|
||||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
|
||||||
|
|
||||||
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
|
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
struct gbm_device *gbm = get_gbm_device ();
|
|
||||||
if (gbm)
|
|
||||||
{
|
|
||||||
uint32_t gbm_format;
|
|
||||||
uint64_t cursor_width, cursor_height;
|
|
||||||
uint width, height;
|
|
||||||
|
|
||||||
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
|
|
||||||
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
|
|
||||||
|
|
||||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
|
|
||||||
if (shm_buffer)
|
|
||||||
{
|
|
||||||
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
|
|
||||||
|
|
||||||
wl_shm_buffer_begin_access (shm_buffer);
|
|
||||||
|
|
||||||
switch (wl_shm_buffer_get_format (shm_buffer))
|
|
||||||
{
|
|
||||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
|
||||||
case WL_SHM_FORMAT_ARGB8888:
|
|
||||||
gbm_format = GBM_FORMAT_ARGB8888;
|
|
||||||
break;
|
|
||||||
case WL_SHM_FORMAT_XRGB8888:
|
|
||||||
gbm_format = GBM_FORMAT_XRGB8888;
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
case WL_SHM_FORMAT_ARGB8888:
|
|
||||||
gbm_format = GBM_FORMAT_ARGB8888;
|
|
||||||
break;
|
|
||||||
case WL_SHM_FORMAT_XRGB8888:
|
|
||||||
gbm_format = GBM_FORMAT_XRGB8888;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
g_warn_if_reached ();
|
|
||||||
gbm_format = GBM_FORMAT_ARGB8888;
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_cursor_image_load_gbm_buffer (gbm,
|
|
||||||
image,
|
|
||||||
(uint8_t *) wl_shm_buffer_get_data (shm_buffer),
|
|
||||||
width, height, rowstride,
|
|
||||||
gbm_format);
|
|
||||||
|
|
||||||
wl_shm_buffer_end_access (shm_buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
|
|
||||||
size, so themed cursors must be padded with transparent pixels to fill the
|
|
||||||
overlay. This is trivial if we have CPU access to the data, but it's not
|
|
||||||
possible if the buffer is in GPU memory (and possibly tiled too), so if we
|
|
||||||
don't get the right size, we fallback to GL.
|
|
||||||
*/
|
|
||||||
get_hardware_cursor_size (&cursor_width, &cursor_height);
|
|
||||||
|
|
||||||
if (width != cursor_width || height != cursor_height)
|
|
||||||
{
|
|
||||||
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER, buffer, GBM_BO_USE_CURSOR);
|
|
||||||
if (!image->bo)
|
|
||||||
meta_warning ("Importing HW cursor from wl_buffer failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
MetaCursorReference *
|
|
||||||
meta_cursor_reference_from_buffer (struct wl_resource *buffer,
|
|
||||||
int hot_x,
|
|
||||||
int hot_y)
|
|
||||||
{
|
|
||||||
MetaCursorReference *self;
|
|
||||||
|
|
||||||
self = g_slice_new0 (MetaCursorReference);
|
|
||||||
self->ref_count = 1;
|
|
||||||
meta_cursor_image_load_from_buffer (&self->image, buffer, hot_x, hot_y);
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
void
|
||||||
|
meta_cursor_sprite_set_texture (MetaCursorSprite *self,
|
||||||
|
CoglTexture *texture,
|
||||||
|
int hot_x,
|
||||||
|
int hot_y)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||||
|
if (texture)
|
||||||
|
self->texture = cogl_object_ref (texture);
|
||||||
|
self->hot_x = hot_x;
|
||||||
|
self->hot_y = hot_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
|
||||||
|
float scale)
|
||||||
|
{
|
||||||
|
self->texture_scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
|
||||||
|
int theme_scale)
|
||||||
|
{
|
||||||
|
if (self->theme_scale != theme_scale)
|
||||||
|
self->theme_dirty = TRUE;
|
||||||
|
self->theme_scale = theme_scale;
|
||||||
|
}
|
||||||
|
|
||||||
CoglTexture *
|
CoglTexture *
|
||||||
meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
|
meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self)
|
||||||
int *hot_x,
|
|
||||||
int *hot_y)
|
|
||||||
{
|
{
|
||||||
if (!cursor->image.texture)
|
return COGL_TEXTURE (self->texture);
|
||||||
load_cursor_image (cursor);
|
|
||||||
|
|
||||||
if (hot_x)
|
|
||||||
*hot_x = cursor->image.hot_x;
|
|
||||||
if (hot_y)
|
|
||||||
*hot_y = cursor->image.hot_y;
|
|
||||||
|
|
||||||
return COGL_TEXTURE (cursor->image.texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_NATIVE_BACKEND
|
|
||||||
struct gbm_bo *
|
|
||||||
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
|
||||||
int *hot_x,
|
|
||||||
int *hot_y)
|
|
||||||
{
|
|
||||||
if (!cursor->image.bo)
|
|
||||||
load_cursor_image (cursor);
|
|
||||||
|
|
||||||
if (hot_x)
|
|
||||||
*hot_x = cursor->image.hot_x;
|
|
||||||
if (hot_y)
|
|
||||||
*hot_y = cursor->image.hot_y;
|
|
||||||
return cursor->image.bo;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MetaCursor
|
MetaCursor
|
||||||
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)
|
meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self)
|
||||||
{
|
{
|
||||||
return cursor->cursor;
|
return self->cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
|
||||||
|
int *hot_x,
|
||||||
|
int *hot_y)
|
||||||
|
{
|
||||||
|
*hot_x = self->hot_x;
|
||||||
|
*hot_y = self->hot_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self)
|
||||||
|
{
|
||||||
|
return self->texture_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
|
{
|
||||||
|
g_signal_emit (self, signals[PREPARE_AT], 0, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_cursor_sprite_realize_texture (MetaCursorSprite *self)
|
||||||
|
{
|
||||||
|
if (self->theme_dirty)
|
||||||
|
meta_cursor_sprite_load_from_theme (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_cursor_sprite_init (MetaCursorSprite *self)
|
||||||
|
{
|
||||||
|
self->texture_scale = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_cursor_sprite_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MetaCursorSprite *self = META_CURSOR_SPRITE (object);
|
||||||
|
|
||||||
|
if (self->xcursor_images)
|
||||||
|
XcursorImagesDestroy (self->xcursor_images);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_cursor_sprite_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_cursor_sprite_class_init (MetaCursorSpriteClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = meta_cursor_sprite_finalize;
|
||||||
|
|
||||||
|
signals[PREPARE_AT] = g_signal_new ("prepare-at",
|
||||||
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_INT,
|
||||||
|
G_TYPE_INT);
|
||||||
}
|
}
|
||||||
|
@@ -22,25 +22,54 @@
|
|||||||
#ifndef META_CURSOR_H
|
#ifndef META_CURSOR_H
|
||||||
#define META_CURSOR_H
|
#define META_CURSOR_H
|
||||||
|
|
||||||
typedef struct _MetaCursorReference MetaCursorReference;
|
|
||||||
|
|
||||||
MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor);
|
|
||||||
void meta_cursor_reference_unref (MetaCursorReference *cursor);
|
|
||||||
|
|
||||||
#include <meta/common.h>
|
#include <meta/common.h>
|
||||||
|
#include <meta/boxes.h>
|
||||||
|
|
||||||
MetaCursorReference * meta_cursor_reference_from_theme (MetaCursor cursor);
|
typedef struct _MetaCursorSprite MetaCursorSprite;
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
#define META_TYPE_CURSOR_SPRITE (meta_cursor_sprite_get_type ())
|
||||||
#include <wayland-server.h>
|
G_DECLARE_FINAL_TYPE (MetaCursorSprite,
|
||||||
MetaCursorReference * meta_cursor_reference_from_buffer (struct wl_resource *buffer,
|
meta_cursor_sprite,
|
||||||
int hot_x,
|
META, CURSOR_SPRITE,
|
||||||
int hot_y);
|
GObject);
|
||||||
#endif
|
|
||||||
|
|
||||||
MetaCursor meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor);
|
MetaCursorSprite * meta_cursor_sprite_new (void);
|
||||||
|
|
||||||
|
MetaCursorSprite * meta_cursor_sprite_from_theme (MetaCursor cursor);
|
||||||
|
|
||||||
|
|
||||||
|
void meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
|
||||||
|
int scale);
|
||||||
|
|
||||||
|
MetaCursor meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self);
|
||||||
|
|
||||||
Cursor meta_cursor_create_x_cursor (Display *xdisplay,
|
Cursor meta_cursor_create_x_cursor (Display *xdisplay,
|
||||||
MetaCursor cursor);
|
MetaCursor cursor);
|
||||||
|
|
||||||
|
void meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
|
||||||
|
int x,
|
||||||
|
int y);
|
||||||
|
|
||||||
|
void meta_cursor_sprite_realize_texture (MetaCursorSprite *self);
|
||||||
|
|
||||||
|
void meta_cursor_sprite_set_texture (MetaCursorSprite *self,
|
||||||
|
CoglTexture *texture,
|
||||||
|
int hot_x,
|
||||||
|
int hot_y);
|
||||||
|
|
||||||
|
void meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
|
||||||
|
float scale);
|
||||||
|
|
||||||
|
CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self);
|
||||||
|
|
||||||
|
void meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
|
||||||
|
int *hot_x,
|
||||||
|
int *hot_y);
|
||||||
|
|
||||||
|
float meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self);
|
||||||
|
|
||||||
|
gboolean meta_cursor_sprite_is_animated (MetaCursorSprite *self);
|
||||||
|
void meta_cursor_sprite_tick_frame (MetaCursorSprite *self);
|
||||||
|
guint meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *self);
|
||||||
|
|
||||||
#endif /* META_CURSOR_H */
|
#endif /* META_CURSOR_H */
|
||||||
|
@@ -174,7 +174,8 @@ struct _MetaCRTC
|
|||||||
/* Used when changing configuration */
|
/* Used when changing configuration */
|
||||||
gboolean is_dirty;
|
gboolean is_dirty;
|
||||||
|
|
||||||
MetaCursorReference *cursor;
|
/* Used by cursor renderer backend */
|
||||||
|
void *cursor_renderer_private;
|
||||||
|
|
||||||
gpointer driver_private;
|
gpointer driver_private;
|
||||||
GDestroyNotify driver_notify;
|
GDestroyNotify driver_notify;
|
||||||
|
@@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include "meta-stage.h"
|
#include "meta-stage.h"
|
||||||
|
|
||||||
#include "meta-cursor-private.h"
|
|
||||||
#include <meta/meta-backend.h>
|
#include <meta/meta-backend.h>
|
||||||
#include <meta/util.h>
|
#include <meta/util.h>
|
||||||
|
|
||||||
|
@@ -328,9 +328,7 @@ meta_backend_native_init (MetaBackendNative *native)
|
|||||||
{
|
{
|
||||||
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
|
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
|
||||||
|
|
||||||
/* We're a display server, so start talking to weston-launch. */
|
|
||||||
priv->launcher = meta_launcher_new ();
|
priv->launcher = meta_launcher_new ();
|
||||||
|
|
||||||
priv->barrier_manager = meta_barrier_manager_native_new ();
|
priv->barrier_manager = meta_barrier_manager_native_new ();
|
||||||
|
|
||||||
priv->up_client = up_client_new ();
|
priv->up_client = up_client_new ();
|
||||||
|
@@ -26,11 +26,16 @@
|
|||||||
|
|
||||||
#include "meta-cursor-renderer-native.h"
|
#include "meta-cursor-renderer-native.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <meta/util.h>
|
||||||
|
#include <meta/meta-backend.h>
|
||||||
|
|
||||||
#include "meta-cursor-private.h"
|
|
||||||
#include "meta-monitor-manager-private.h"
|
#include "meta-monitor-manager-private.h"
|
||||||
|
#include "meta/boxes.h"
|
||||||
|
|
||||||
#ifndef DRM_CAP_CURSOR_WIDTH
|
#ifndef DRM_CAP_CURSOR_WIDTH
|
||||||
#define DRM_CAP_CURSOR_WIDTH 0x8
|
#define DRM_CAP_CURSOR_WIDTH 0x8
|
||||||
@@ -39,11 +44,26 @@
|
|||||||
#define DRM_CAP_CURSOR_HEIGHT 0x9
|
#define DRM_CAP_CURSOR_HEIGHT 0x9
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* When animating a cursor, we usually call drmModeSetCursor2 once per frame.
|
||||||
|
* Though, testing shows that we need to triple buffer the cursor buffer in
|
||||||
|
* order to avoid glitches when animating the cursor, at least when running on
|
||||||
|
* Intel. The reason for this might be (but is not confirmed to be) due to
|
||||||
|
* the user space gbm_bo cache, making us reuse and overwrite the kernel side
|
||||||
|
* buffer content before it was scanned out. To avoid this, we keep a user space
|
||||||
|
* reference to each buffer we set until at least one frame after it was drawn.
|
||||||
|
* In effect, this means we three active cursor gbm_bo's: one that that just has
|
||||||
|
* been set, one that was previously set and may or may not have been scanned
|
||||||
|
* out, and one pending that will be replaced if the cursor sprite changes.
|
||||||
|
*/
|
||||||
|
#define HW_CURSOR_BUFFER_COUNT 3
|
||||||
|
|
||||||
|
static GQuark quark_cursor_sprite = 0;
|
||||||
|
|
||||||
struct _MetaCursorRendererNativePrivate
|
struct _MetaCursorRendererNativePrivate
|
||||||
{
|
{
|
||||||
gboolean has_hw_cursor;
|
gboolean has_hw_cursor;
|
||||||
|
|
||||||
MetaCursorReference *last_cursor;
|
MetaCursorSprite *last_cursor;
|
||||||
guint animation_timeout_id;
|
guint animation_timeout_id;
|
||||||
|
|
||||||
int drm_fd;
|
int drm_fd;
|
||||||
@@ -54,8 +74,25 @@ struct _MetaCursorRendererNativePrivate
|
|||||||
};
|
};
|
||||||
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
|
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
|
||||||
|
|
||||||
|
typedef enum _MetaCursorGbmBoState
|
||||||
|
{
|
||||||
|
META_CURSOR_GBM_BO_STATE_NONE,
|
||||||
|
META_CURSOR_GBM_BO_STATE_SET,
|
||||||
|
META_CURSOR_GBM_BO_STATE_INVALIDATED,
|
||||||
|
} MetaCursorGbmBoState;
|
||||||
|
|
||||||
|
typedef struct _MetaCursorNativePrivate
|
||||||
|
{
|
||||||
|
guint active_bo;
|
||||||
|
MetaCursorGbmBoState pending_bo_state;
|
||||||
|
struct gbm_bo *bos[HW_CURSOR_BUFFER_COUNT];
|
||||||
|
} MetaCursorNativePrivate;
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
|
||||||
|
|
||||||
|
static MetaCursorNativePrivate *
|
||||||
|
ensure_cursor_priv (MetaCursorSprite *cursor_sprite);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_cursor_renderer_native_finalize (GObject *object)
|
meta_cursor_renderer_native_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
@@ -71,63 +108,136 @@ meta_cursor_renderer_native_finalize (GObject *object)
|
|||||||
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
get_pending_cursor_sprite_gbm_bo_index (MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv =
|
||||||
|
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
|
||||||
|
|
||||||
|
return (cursor_priv->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gbm_bo *
|
||||||
|
get_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv =
|
||||||
|
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
|
||||||
|
guint pending_bo;
|
||||||
|
|
||||||
|
if (!cursor_priv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
|
||||||
|
return cursor_priv->bos[pending_bo];
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gbm_bo *
|
||||||
|
get_active_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 NULL;
|
||||||
|
|
||||||
|
return cursor_priv->bos[cursor_priv->active_bo];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
|
||||||
|
struct gbm_bo *bo)
|
||||||
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv;
|
||||||
|
guint pending_bo;
|
||||||
|
|
||||||
|
cursor_priv = ensure_cursor_priv (cursor_sprite);
|
||||||
|
|
||||||
|
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
|
||||||
|
cursor_priv->bos[pending_bo] = bo;
|
||||||
|
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_SET;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_crtc_cursor (MetaCursorRendererNative *native,
|
set_crtc_cursor (MetaCursorRendererNative *native,
|
||||||
MetaCRTC *crtc,
|
MetaCRTC *crtc,
|
||||||
MetaCursorReference *cursor,
|
MetaCursorSprite *cursor_sprite,
|
||||||
gboolean force)
|
gboolean force)
|
||||||
{
|
{
|
||||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||||
|
|
||||||
if (crtc->cursor == cursor && !force)
|
if (cursor_sprite)
|
||||||
return;
|
|
||||||
|
|
||||||
crtc->cursor = cursor;
|
|
||||||
|
|
||||||
if (cursor)
|
|
||||||
{
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv =
|
||||||
|
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
|
||||||
struct gbm_bo *bo;
|
struct gbm_bo *bo;
|
||||||
union gbm_bo_handle handle;
|
union gbm_bo_handle handle;
|
||||||
int hot_x, hot_y;
|
int hot_x, hot_y;
|
||||||
|
|
||||||
bo = meta_cursor_reference_get_gbm_bo (cursor, &hot_x, &hot_y);
|
if (cursor_priv->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
|
||||||
|
bo = get_pending_cursor_sprite_gbm_bo (cursor_sprite);
|
||||||
|
else
|
||||||
|
bo = get_active_cursor_sprite_gbm_bo (cursor_sprite);
|
||||||
|
|
||||||
|
if (!force && bo == crtc->cursor_renderer_private)
|
||||||
|
return;
|
||||||
|
|
||||||
|
crtc->cursor_renderer_private = bo;
|
||||||
|
|
||||||
handle = gbm_bo_get_handle (bo);
|
handle = gbm_bo_get_handle (bo);
|
||||||
|
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
|
||||||
|
|
||||||
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
|
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
|
||||||
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
|
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
|
||||||
|
|
||||||
|
if (cursor_priv->pending_bo_state == META_CURSOR_GBM_BO_STATE_SET)
|
||||||
|
{
|
||||||
|
cursor_priv->active_bo =
|
||||||
|
(cursor_priv->active_bo + 1) % HW_CURSOR_BUFFER_COUNT;
|
||||||
|
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
|
if (force || crtc->cursor_renderer_private != NULL)
|
||||||
|
{
|
||||||
|
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
|
||||||
|
crtc->cursor_renderer_private = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_hw_cursor (MetaCursorRendererNative *native,
|
update_hw_cursor (MetaCursorRendererNative *native,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
gboolean force)
|
gboolean force)
|
||||||
{
|
{
|
||||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||||
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
||||||
const MetaRectangle *cursor_rect = meta_cursor_renderer_get_rect (renderer);
|
|
||||||
MetaCursorReference *cursor = meta_cursor_renderer_get_cursor (renderer);
|
|
||||||
MetaMonitorManager *monitors;
|
MetaMonitorManager *monitors;
|
||||||
MetaCRTC *crtcs;
|
MetaCRTC *crtcs;
|
||||||
unsigned int i, n_crtcs;
|
unsigned int i, n_crtcs;
|
||||||
|
MetaRectangle rect;
|
||||||
|
|
||||||
monitors = meta_monitor_manager_get ();
|
monitors = meta_monitor_manager_get ();
|
||||||
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
|
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
|
||||||
|
|
||||||
|
if (cursor_sprite)
|
||||||
|
rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
|
||||||
|
else
|
||||||
|
rect = (MetaRectangle) { 0 };
|
||||||
|
|
||||||
for (i = 0; i < n_crtcs; i++)
|
for (i = 0; i < n_crtcs; i++)
|
||||||
{
|
{
|
||||||
gboolean crtc_should_have_cursor;
|
gboolean crtc_should_use_cursor;
|
||||||
MetaCursorReference *crtc_cursor;
|
MetaCursorSprite *crtc_cursor;
|
||||||
MetaRectangle *crtc_rect;
|
MetaRectangle *crtc_rect;
|
||||||
|
|
||||||
crtc_rect = &crtcs[i].rect;
|
crtc_rect = &crtcs[i].rect;
|
||||||
|
|
||||||
crtc_should_have_cursor = (priv->has_hw_cursor && meta_rectangle_overlap (cursor_rect, crtc_rect));
|
crtc_should_use_cursor = (priv->has_hw_cursor &&
|
||||||
if (crtc_should_have_cursor)
|
meta_rectangle_overlap (&rect, crtc_rect));
|
||||||
crtc_cursor = cursor;
|
if (crtc_should_use_cursor)
|
||||||
|
crtc_cursor = cursor_sprite;
|
||||||
else
|
else
|
||||||
crtc_cursor = NULL;
|
crtc_cursor = NULL;
|
||||||
|
|
||||||
@@ -136,49 +246,79 @@ update_hw_cursor (MetaCursorRendererNative *native,
|
|||||||
if (crtc_cursor)
|
if (crtc_cursor)
|
||||||
{
|
{
|
||||||
drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id,
|
drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id,
|
||||||
cursor_rect->x - crtc_rect->x,
|
rect.x - crtc_rect->x,
|
||||||
cursor_rect->y - crtc_rect->y);
|
rect.y - crtc_rect->y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
should_have_hw_cursor (MetaCursorRenderer *renderer)
|
has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorReference *cursor = meta_cursor_renderer_get_cursor (renderer);
|
MetaCursorNativePrivate *cursor_priv =
|
||||||
|
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
|
||||||
|
|
||||||
if (cursor)
|
switch (cursor_priv->pending_bo_state)
|
||||||
return (meta_cursor_reference_get_gbm_bo (cursor, NULL, NULL) != NULL);
|
{
|
||||||
else
|
case META_CURSOR_GBM_BO_STATE_NONE:
|
||||||
|
return get_active_cursor_sprite_gbm_bo (cursor_sprite) != NULL;
|
||||||
|
case META_CURSOR_GBM_BO_STATE_SET:
|
||||||
|
return TRUE;
|
||||||
|
case META_CURSOR_GBM_BO_STATE_INVALIDATED:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
should_have_hw_cursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
CoglTexture *texture;
|
||||||
|
|
||||||
|
if (!cursor_sprite)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
||||||
|
if (!texture)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (meta_cursor_sprite_get_texture_scale (cursor_sprite) != 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
|
meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
|
||||||
{
|
{
|
||||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||||
MetaCursorReference *cursor;
|
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
||||||
|
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
|
||||||
|
|
||||||
priv->animation_timeout_id = 0;
|
priv->animation_timeout_id = 0;
|
||||||
cursor = meta_cursor_renderer_get_cursor (META_CURSOR_RENDERER (native));
|
meta_cursor_sprite_tick_frame (cursor_sprite);
|
||||||
meta_cursor_reference_tick_frame (cursor);
|
meta_cursor_renderer_force_update (renderer);
|
||||||
meta_cursor_renderer_force_update (META_CURSOR_RENDERER (native));
|
|
||||||
meta_cursor_renderer_native_force_update (native);
|
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native)
|
meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||||
MetaCursorReference *cursor;
|
|
||||||
gboolean cursor_change;
|
gboolean cursor_change;
|
||||||
guint delay;
|
guint delay;
|
||||||
|
|
||||||
cursor = meta_cursor_renderer_get_cursor (META_CURSOR_RENDERER (native));
|
cursor_change = cursor_sprite != priv->last_cursor;
|
||||||
cursor_change = cursor != priv->last_cursor;
|
priv->last_cursor = cursor_sprite;
|
||||||
priv->last_cursor = cursor;
|
|
||||||
|
|
||||||
if (!cursor_change && priv->animation_timeout_id)
|
if (!cursor_change && priv->animation_timeout_id)
|
||||||
return;
|
return;
|
||||||
@@ -189,9 +329,9 @@ meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native)
|
|||||||
priv->animation_timeout_id = 0;
|
priv->animation_timeout_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor && meta_cursor_reference_is_animated (cursor))
|
if (cursor_sprite && meta_cursor_sprite_is_animated (cursor_sprite))
|
||||||
{
|
{
|
||||||
delay = meta_cursor_reference_get_current_frame_time (cursor);
|
delay = meta_cursor_sprite_get_current_frame_time (cursor_sprite);
|
||||||
|
|
||||||
if (delay == 0)
|
if (delay == 0)
|
||||||
return;
|
return;
|
||||||
@@ -206,18 +346,250 @@ meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer)
|
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||||
|
|
||||||
meta_cursor_renderer_native_trigger_frame (native);
|
if (cursor_sprite)
|
||||||
|
meta_cursor_sprite_realize_texture (cursor_sprite);
|
||||||
|
|
||||||
priv->has_hw_cursor = should_have_hw_cursor (renderer);
|
meta_cursor_renderer_native_trigger_frame (native, cursor_sprite);
|
||||||
update_hw_cursor (native, FALSE);
|
|
||||||
|
priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite);
|
||||||
|
update_hw_cursor (native, cursor_sprite, FALSE);
|
||||||
return priv->has_hw_cursor;
|
return priv->has_hw_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_hardware_cursor_size (MetaCursorRendererNative *native,
|
||||||
|
uint64_t *width, uint64_t *height)
|
||||||
|
{
|
||||||
|
MetaCursorRendererNativePrivate *priv =
|
||||||
|
meta_cursor_renderer_native_get_instance_private (native);
|
||||||
|
|
||||||
|
*width = priv->cursor_width;
|
||||||
|
*height = priv->cursor_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_priv_free (gpointer data)
|
||||||
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv = data;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++)
|
||||||
|
g_clear_pointer (&cursor_priv->bos[0], (GDestroyNotify) gbm_bo_destroy);
|
||||||
|
g_slice_free (MetaCursorNativePrivate, cursor_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaCursorNativePrivate *
|
||||||
|
ensure_cursor_priv (MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv =
|
||||||
|
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
|
||||||
|
|
||||||
|
if (!cursor_priv)
|
||||||
|
{
|
||||||
|
cursor_priv = g_slice_new0 (MetaCursorNativePrivate);
|
||||||
|
g_object_set_qdata_full (G_OBJECT (cursor_sprite),
|
||||||
|
quark_cursor_sprite,
|
||||||
|
cursor_priv,
|
||||||
|
cursor_priv_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cursor_priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
uint8_t *pixels,
|
||||||
|
uint width,
|
||||||
|
uint height,
|
||||||
|
int rowstride,
|
||||||
|
uint32_t gbm_format)
|
||||||
|
{
|
||||||
|
MetaCursorRendererNativePrivate *priv =
|
||||||
|
meta_cursor_renderer_native_get_instance_private (native);
|
||||||
|
uint64_t cursor_width, cursor_height;
|
||||||
|
|
||||||
|
get_hardware_cursor_size (native, &cursor_width, &cursor_height);
|
||||||
|
|
||||||
|
if (width > cursor_width || height > cursor_height)
|
||||||
|
{
|
||||||
|
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
|
||||||
|
(unsigned int)cursor_width, (unsigned int)cursor_height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gbm_device_is_format_supported (priv->gbm, gbm_format,
|
||||||
|
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
|
||||||
|
{
|
||||||
|
struct gbm_bo *bo;
|
||||||
|
uint8_t buf[4 * cursor_width * cursor_height];
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
bo = gbm_bo_create (priv->gbm, cursor_width, cursor_height,
|
||||||
|
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
||||||
|
if (!bo)
|
||||||
|
{
|
||||||
|
meta_warning ("Failed to allocate HW cursor buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (buf, 0, sizeof(buf));
|
||||||
|
for (i = 0; i < height; i++)
|
||||||
|
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
|
||||||
|
if (gbm_bo_write (bo, buf, cursor_width * cursor_height * 4) != 0)
|
||||||
|
{
|
||||||
|
meta_warning ("Failed to write cursors buffer data: %s",
|
||||||
|
g_strerror (errno));
|
||||||
|
gbm_bo_destroy (bo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_pending_cursor_sprite_gbm_bo (cursor_sprite, bo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
invalidate_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
MetaCursorNativePrivate *cursor_priv =
|
||||||
|
g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
|
||||||
|
guint pending_bo;
|
||||||
|
|
||||||
|
if (!cursor_priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_sprite);
|
||||||
|
g_clear_pointer (&cursor_priv->bos[pending_bo],
|
||||||
|
(GDestroyNotify) gbm_bo_destroy);
|
||||||
|
cursor_priv->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
static void
|
||||||
|
meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
struct wl_resource *buffer)
|
||||||
|
{
|
||||||
|
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||||
|
MetaCursorRendererNativePrivate *priv =
|
||||||
|
meta_cursor_renderer_native_get_instance_private (native);
|
||||||
|
uint32_t gbm_format;
|
||||||
|
uint64_t cursor_width, cursor_height;
|
||||||
|
CoglTexture *texture;
|
||||||
|
uint width, height;
|
||||||
|
|
||||||
|
/* Destroy any previous pending cursor buffer; we'll always either fail (which
|
||||||
|
* should unset, or succeed, which will set new buffer.
|
||||||
|
*/
|
||||||
|
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite);
|
||||||
|
|
||||||
|
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
||||||
|
width = cogl_texture_get_width (texture);
|
||||||
|
height = cogl_texture_get_height (texture);
|
||||||
|
|
||||||
|
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
|
||||||
|
if (shm_buffer)
|
||||||
|
{
|
||||||
|
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
|
||||||
|
uint8_t *buffer_data;
|
||||||
|
|
||||||
|
wl_shm_buffer_begin_access (shm_buffer);
|
||||||
|
|
||||||
|
switch (wl_shm_buffer_get_format (shm_buffer))
|
||||||
|
{
|
||||||
|
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||||
|
case WL_SHM_FORMAT_ARGB8888:
|
||||||
|
gbm_format = GBM_FORMAT_ARGB8888;
|
||||||
|
break;
|
||||||
|
case WL_SHM_FORMAT_XRGB8888:
|
||||||
|
gbm_format = GBM_FORMAT_XRGB8888;
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
case WL_SHM_FORMAT_ARGB8888:
|
||||||
|
gbm_format = GBM_FORMAT_ARGB8888;
|
||||||
|
break;
|
||||||
|
case WL_SHM_FORMAT_XRGB8888:
|
||||||
|
gbm_format = GBM_FORMAT_XRGB8888;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
g_warn_if_reached ();
|
||||||
|
gbm_format = GBM_FORMAT_ARGB8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_data = wl_shm_buffer_get_data (shm_buffer);
|
||||||
|
load_cursor_sprite_gbm_buffer (native,
|
||||||
|
cursor_sprite,
|
||||||
|
buffer_data,
|
||||||
|
width, height, rowstride,
|
||||||
|
gbm_format);
|
||||||
|
|
||||||
|
wl_shm_buffer_end_access (shm_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct gbm_bo *bo;
|
||||||
|
|
||||||
|
/* HW cursors have a predefined size (at least 64x64), which usually is
|
||||||
|
* bigger than cursor theme size, so themed cursors must be padded with
|
||||||
|
* transparent pixels to fill the overlay. This is trivial if we have CPU
|
||||||
|
* access to the data, but it's not possible if the buffer is in GPU
|
||||||
|
* memory (and possibly tiled too), so if we don't get the right size, we
|
||||||
|
* fallback to GL. */
|
||||||
|
get_hardware_cursor_size (native, &cursor_width, &cursor_height);
|
||||||
|
|
||||||
|
if (width != cursor_width || height != cursor_height)
|
||||||
|
{
|
||||||
|
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo = gbm_bo_import (priv->gbm,
|
||||||
|
GBM_BO_IMPORT_WL_BUFFER,
|
||||||
|
buffer,
|
||||||
|
GBM_BO_USE_CURSOR);
|
||||||
|
if (!bo)
|
||||||
|
{
|
||||||
|
meta_warning ("Importing HW cursor from wl_buffer failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_pending_cursor_sprite_gbm_bo (cursor_sprite, bo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite,
|
||||||
|
XcursorImage *xc_image)
|
||||||
|
{
|
||||||
|
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||||
|
|
||||||
|
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite);
|
||||||
|
|
||||||
|
load_cursor_sprite_gbm_buffer (native,
|
||||||
|
cursor_sprite,
|
||||||
|
(uint8_t *) xc_image->pixels,
|
||||||
|
xc_image->width,
|
||||||
|
xc_image->height,
|
||||||
|
xc_image->width * 4,
|
||||||
|
GBM_FORMAT_ARGB8888);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
|
meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
|
||||||
{
|
{
|
||||||
@@ -226,6 +598,22 @@ meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
|
|||||||
|
|
||||||
object_class->finalize = meta_cursor_renderer_native_finalize;
|
object_class->finalize = meta_cursor_renderer_native_finalize;
|
||||||
renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
|
renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
renderer_class->realize_cursor_from_wl_buffer =
|
||||||
|
meta_cursor_renderer_native_realize_cursor_from_wl_buffer;
|
||||||
|
#endif
|
||||||
|
renderer_class->realize_cursor_from_xcursor =
|
||||||
|
meta_cursor_renderer_native_realize_cursor_from_xcursor;
|
||||||
|
|
||||||
|
quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
force_update_hw_cursor (MetaCursorRendererNative *native)
|
||||||
|
{
|
||||||
|
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
||||||
|
|
||||||
|
update_hw_cursor (native, meta_cursor_renderer_get_cursor (renderer), TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -233,7 +621,7 @@ on_monitors_changed (MetaMonitorManager *monitors,
|
|||||||
MetaCursorRendererNative *native)
|
MetaCursorRendererNative *native)
|
||||||
{
|
{
|
||||||
/* Our tracking is all messed up, so force an update. */
|
/* Our tracking is all messed up, so force an update. */
|
||||||
update_hw_cursor (native, TRUE);
|
force_update_hw_cursor (native);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -278,18 +666,8 @@ meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
|
|||||||
return priv->gbm;
|
return priv->gbm;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native,
|
|
||||||
uint64_t *width, uint64_t *height)
|
|
||||||
{
|
|
||||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
|
||||||
|
|
||||||
*width = priv->cursor_width;
|
|
||||||
*height = priv->cursor_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
|
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
|
||||||
{
|
{
|
||||||
update_hw_cursor (native, TRUE);
|
force_update_hw_cursor (native);
|
||||||
}
|
}
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <systemd/sd-login.h>
|
#include <systemd/sd-login.h>
|
||||||
|
#include <gudev/gudev.h>
|
||||||
|
|
||||||
#include "dbus-utils.h"
|
#include "dbus-utils.h"
|
||||||
#include "meta-dbus-login1.h"
|
#include "meta-dbus-login1.h"
|
||||||
@@ -53,12 +54,27 @@ struct _MetaLauncher
|
|||||||
gboolean session_active;
|
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 *
|
static Login1Session *
|
||||||
get_session_proxy (GCancellable *cancellable)
|
get_session_proxy (GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
char *proxy_path;
|
char *proxy_path;
|
||||||
char *session_id;
|
char *session_id;
|
||||||
Login1Session *session_proxy;
|
Login1Session *session_proxy;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
if (sd_pid_get_session (getpid (), &session_id) < 0)
|
if (sd_pid_get_session (getpid (), &session_id) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -69,7 +85,10 @@ get_session_proxy (GCancellable *cancellable)
|
|||||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||||
"org.freedesktop.login1",
|
"org.freedesktop.login1",
|
||||||
proxy_path,
|
proxy_path,
|
||||||
cancellable, NULL);
|
cancellable, &error);
|
||||||
|
if (!session_proxy)
|
||||||
|
report_error_and_die ("Failed getting session proxy", error);
|
||||||
|
|
||||||
free (proxy_path);
|
free (proxy_path);
|
||||||
|
|
||||||
return session_proxy;
|
return session_proxy;
|
||||||
@@ -78,11 +97,16 @@ get_session_proxy (GCancellable *cancellable)
|
|||||||
static Login1Seat *
|
static Login1Seat *
|
||||||
get_seat_proxy (GCancellable *cancellable)
|
get_seat_proxy (GCancellable *cancellable)
|
||||||
{
|
{
|
||||||
return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
GError *error = NULL;
|
||||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
Login1Seat *seat = login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||||
"org.freedesktop.login1",
|
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||||
"/org/freedesktop/login1/seat/self",
|
"org.freedesktop.login1",
|
||||||
cancellable, NULL);
|
"/org/freedesktop/login1/seat/self",
|
||||||
|
cancellable, &error);
|
||||||
|
if (!seat)
|
||||||
|
report_error_and_die ("Could not get seat proxy", error);
|
||||||
|
|
||||||
|
return seat;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -223,7 +247,7 @@ on_evdev_device_close (int fd,
|
|||||||
if (!get_device_info_from_fd (fd, &major, &minor))
|
if (!get_device_info_from_fd (fd, &major, &minor))
|
||||||
{
|
{
|
||||||
g_warning ("Could not get device info for fd %d: %m", fd);
|
g_warning ("Could not get device info for fd %d: %m", fd);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!login1_session_call_release_device_sync (self->session_proxy,
|
if (!login1_session_call_release_device_sync (self->session_proxy,
|
||||||
@@ -232,6 +256,9 @@ on_evdev_device_close (int fd,
|
|||||||
{
|
{
|
||||||
g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
|
g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
close (fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -259,31 +286,115 @@ on_active_changed (Login1Session *session,
|
|||||||
sync_active (self);
|
sync_active (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gchar *
|
||||||
|
get_primary_gpu_path (const gchar *seat_name)
|
||||||
|
{
|
||||||
|
const gchar *subsystems[] = {"drm", NULL};
|
||||||
|
gchar *path = NULL;
|
||||||
|
GList *devices, *tmp;
|
||||||
|
|
||||||
|
GUdevClient *gudev_client = g_udev_client_new (subsystems);
|
||||||
|
GUdevEnumerator *enumerator = g_udev_enumerator_new (gudev_client);
|
||||||
|
|
||||||
|
g_udev_enumerator_add_match_name (enumerator, "card*");
|
||||||
|
g_udev_enumerator_add_match_tag (enumerator, "seat");
|
||||||
|
|
||||||
|
devices = g_udev_enumerator_execute (enumerator);
|
||||||
|
if (!devices)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for (tmp = devices; tmp != NULL; tmp = tmp->next)
|
||||||
|
{
|
||||||
|
GUdevDevice *pci_device;
|
||||||
|
GUdevDevice *dev = tmp->data;
|
||||||
|
gint boot_vga;
|
||||||
|
const gchar *device_seat;
|
||||||
|
|
||||||
|
/* filter out devices that are not character device, like card0-VGA-1 */
|
||||||
|
if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
device_seat = g_udev_device_get_property (dev, "ID_SEAT");
|
||||||
|
if (!device_seat)
|
||||||
|
{
|
||||||
|
/* when ID_SEAT is not set, it means seat0 */
|
||||||
|
device_seat = "seat0";
|
||||||
|
}
|
||||||
|
else if (g_strcmp0 (device_seat, "seat0") != 0)
|
||||||
|
{
|
||||||
|
/* if the device has been explicitly assigned other seat
|
||||||
|
* than seat0, it is probably the right device to use */
|
||||||
|
path = g_strdup (g_udev_device_get_device_file (dev));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip devices that do not belong to our seat */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* 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
|
||||||
get_kms_fd (Login1Session *session_proxy,
|
get_kms_fd (Login1Session *session_proxy,
|
||||||
|
const gchar *seat_id,
|
||||||
int *fd_out)
|
int *fd_out)
|
||||||
{
|
{
|
||||||
int major, minor;
|
int major, minor;
|
||||||
int fd;
|
int fd;
|
||||||
|
gchar *path;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
/* XXX -- use udev to find the DRM master device */
|
path = get_primary_gpu_path (seat_id);
|
||||||
if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
|
if (!path)
|
||||||
{
|
g_error ("could not find drm kms device");
|
||||||
g_warning ("Could not stat /dev/dri/card0: %m");
|
|
||||||
return FALSE;
|
if (!get_device_info_from_path (path, &major, &minor))
|
||||||
}
|
g_error ("Could not stat %s: %m", path);
|
||||||
|
|
||||||
|
g_free (path);
|
||||||
|
|
||||||
if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
|
if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
|
||||||
{
|
report_error_and_die ("Could not open DRM device", error);
|
||||||
g_warning ("Could not open DRM device: %s\n", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*fd_out = fd;
|
*fd_out = fd;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
static gchar *
|
||||||
|
get_seat_id (void)
|
||||||
|
{
|
||||||
|
char *session_id, *seat_id = NULL;
|
||||||
|
|
||||||
|
if (sd_pid_get_session (0, &session_id) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* on error the seat_id will remain NULL */
|
||||||
|
sd_session_get_seat (session_id, &seat_id);
|
||||||
|
free (session_id);
|
||||||
|
|
||||||
|
return seat_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaLauncher *
|
MetaLauncher *
|
||||||
@@ -291,22 +402,23 @@ meta_launcher_new (void)
|
|||||||
{
|
{
|
||||||
MetaLauncher *self = NULL;
|
MetaLauncher *self = NULL;
|
||||||
Login1Session *session_proxy;
|
Login1Session *session_proxy;
|
||||||
|
char *seat_id;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
int kms_fd;
|
int kms_fd;
|
||||||
|
|
||||||
session_proxy = get_session_proxy (NULL);
|
session_proxy = get_session_proxy (NULL);
|
||||||
if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
|
if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
|
||||||
{
|
report_error_and_die ("Could not take control", error);
|
||||||
g_warning ("Could not take control: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_kms_fd (session_proxy, &kms_fd))
|
seat_id = get_seat_id ();
|
||||||
goto out;
|
if (!seat_id)
|
||||||
|
g_error ("Failed getting seat id");
|
||||||
|
|
||||||
|
get_kms_fd (session_proxy, seat_id, &kms_fd);
|
||||||
|
free (seat_id);
|
||||||
|
|
||||||
self = g_slice_new0 (MetaLauncher);
|
self = g_slice_new0 (MetaLauncher);
|
||||||
self->session_proxy = g_object_ref (session_proxy);
|
self->session_proxy = session_proxy;
|
||||||
self->seat_proxy = get_seat_proxy (NULL);
|
self->seat_proxy = get_seat_proxy (NULL);
|
||||||
|
|
||||||
self->session_active = TRUE;
|
self->session_active = TRUE;
|
||||||
@@ -318,9 +430,6 @@ meta_launcher_new (void)
|
|||||||
|
|
||||||
g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
|
g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
|
||||||
|
|
||||||
out:
|
|
||||||
g_object_unref (session_proxy);
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,7 +40,11 @@
|
|||||||
#include "meta-idle-monitor-xsync.h"
|
#include "meta-idle-monitor-xsync.h"
|
||||||
#include "meta-monitor-manager-xrandr.h"
|
#include "meta-monitor-manager-xrandr.h"
|
||||||
#include "backends/meta-monitor-manager-dummy.h"
|
#include "backends/meta-monitor-manager-dummy.h"
|
||||||
|
#include "backends/x11/nested/meta-cursor-renderer-x11-nested.h"
|
||||||
#include "meta-cursor-renderer-x11.h"
|
#include "meta-cursor-renderer-x11.h"
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
#include "wayland/meta-wayland.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <meta/util.h>
|
#include <meta/util.h>
|
||||||
#include "display-private.h"
|
#include "display-private.h"
|
||||||
@@ -154,10 +158,9 @@ translate_crossing_event (MetaBackendX11 *x11,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Window stage_window = meta_backend_x11_get_xwindow (x11);
|
Window stage_window = meta_backend_x11_get_xwindow (x11);
|
||||||
if (enter_event->event != stage_window)
|
if (enter_event->event != stage_window &&
|
||||||
|
priv->mode == META_BACKEND_X11_MODE_COMPOSITOR)
|
||||||
{
|
{
|
||||||
/* See above for the rationale for this... */
|
|
||||||
g_assert (priv->mode == META_BACKEND_X11_MODE_COMPOSITOR);
|
|
||||||
enter_event->event = meta_backend_x11_get_xwindow (x11);
|
enter_event->event = meta_backend_x11_get_xwindow (x11);
|
||||||
enter_event->event_x = enter_event->root_x;
|
enter_event->event_x = enter_event->root_x;
|
||||||
enter_event->event_y = enter_event->root_y;
|
enter_event->event_y = enter_event->root_y;
|
||||||
@@ -270,6 +273,25 @@ handle_host_xevent (MetaBackend *backend,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->mode == META_BACKEND_X11_MODE_NESTED && event->type == FocusIn)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_WAYLAND
|
||||||
|
Window xwin = meta_backend_x11_get_xwindow(x11);
|
||||||
|
XEvent xev;
|
||||||
|
|
||||||
|
if (event->xfocus.window == xwin)
|
||||||
|
{
|
||||||
|
/* Since we've selected for KeymapStateMask, every FocusIn is followed immediately
|
||||||
|
* by a KeymapNotify event */
|
||||||
|
XMaskEvent(priv->xdisplay, KeymapStateMask, &xev);
|
||||||
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||||
|
meta_wayland_compositor_update_key_state (compositor, xev.xkeymap.key_vector, 32, 8);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (event->type == (priv->xsync_event_base + XSyncAlarmNotify))
|
if (event->type == (priv->xsync_event_base + XSyncAlarmNotify))
|
||||||
handle_alarm_notify (backend, event);
|
handle_alarm_notify (backend, event);
|
||||||
|
|
||||||
@@ -500,7 +522,20 @@ meta_backend_x11_create_monitor_manager (MetaBackend *backend)
|
|||||||
static MetaCursorRenderer *
|
static MetaCursorRenderer *
|
||||||
meta_backend_x11_create_cursor_renderer (MetaBackend *backend)
|
meta_backend_x11_create_cursor_renderer (MetaBackend *backend)
|
||||||
{
|
{
|
||||||
return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL);
|
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||||
|
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||||
|
|
||||||
|
switch (priv->mode)
|
||||||
|
{
|
||||||
|
case META_BACKEND_X11_MODE_COMPOSITOR:
|
||||||
|
return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL);
|
||||||
|
break;
|
||||||
|
case META_BACKEND_X11_MODE_NESTED:
|
||||||
|
return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -801,6 +836,20 @@ meta_backend_x11_select_stage_events (MetaBackend *backend)
|
|||||||
}
|
}
|
||||||
|
|
||||||
XISelectEvents (priv->xdisplay, xwin, &mask, 1);
|
XISelectEvents (priv->xdisplay, xwin, &mask, 1);
|
||||||
|
|
||||||
|
if (priv->mode == META_BACKEND_X11_MODE_NESTED)
|
||||||
|
{
|
||||||
|
/* We have no way of tracking key changes when the stage doesn't have
|
||||||
|
* focus, so we select for KeymapStateMask so that we get a complete
|
||||||
|
* dump of the keyboard state in a KeymapNotify event that immediately
|
||||||
|
* follows each FocusIn (and EnterNotify, but we ignore that.)
|
||||||
|
*/
|
||||||
|
XWindowAttributes xwa;
|
||||||
|
|
||||||
|
XGetWindowAttributes(priv->xdisplay, xwin, &xwa);
|
||||||
|
XSelectInput(priv->xdisplay, xwin,
|
||||||
|
xwa.your_event_mask | FocusChangeMask | KeymapStateMask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -40,25 +40,29 @@ typedef struct _MetaCursorRendererX11Private MetaCursorRendererX11Private;
|
|||||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererX11, meta_cursor_renderer_x11, META_TYPE_CURSOR_RENDERER);
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererX11, meta_cursor_renderer_x11, META_TYPE_CURSOR_RENDERER);
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer)
|
meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursorRendererX11 *x11 = META_CURSOR_RENDERER_X11 (renderer);
|
MetaCursorRendererX11 *x11 = META_CURSOR_RENDERER_X11 (renderer);
|
||||||
MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11);
|
MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11);
|
||||||
|
|
||||||
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
||||||
Window xwindow = meta_backend_x11_get_xwindow (backend);
|
Window xwindow = meta_backend_x11_get_xwindow (backend);
|
||||||
|
|
||||||
if (xwindow == None)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
|
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
|
||||||
|
|
||||||
MetaCursorReference *cursor_ref = meta_cursor_renderer_get_cursor (renderer);
|
if (xwindow == None)
|
||||||
|
{
|
||||||
|
if (cursor_sprite)
|
||||||
|
meta_cursor_sprite_realize_texture (cursor_sprite);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean has_server_cursor = FALSE;
|
gboolean has_server_cursor = FALSE;
|
||||||
|
|
||||||
if (cursor_ref)
|
if (cursor_sprite)
|
||||||
{
|
{
|
||||||
MetaCursor cursor = meta_cursor_reference_get_meta_cursor (cursor_ref);
|
MetaCursor cursor = meta_cursor_sprite_get_meta_cursor (cursor_sprite);
|
||||||
|
|
||||||
if (cursor != META_CURSOR_NONE)
|
if (cursor != META_CURSOR_NONE)
|
||||||
{
|
{
|
||||||
Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor);
|
Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor);
|
||||||
@@ -80,6 +84,9 @@ meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer)
|
|||||||
priv->server_cursor_visible = has_server_cursor;
|
priv->server_cursor_visible = has_server_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!priv->server_cursor_visible && cursor_sprite)
|
||||||
|
meta_cursor_sprite_realize_texture (cursor_sprite);
|
||||||
|
|
||||||
return priv->server_cursor_visible;
|
return priv->server_cursor_visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
src/backends/x11/nested/meta-cursor-renderer-x11-nested.c
Normal file
91
src/backends/x11/nested/meta-cursor-renderer-x11-nested.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/* -*- 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/x11/nested/meta-cursor-renderer-x11-nested.h"
|
||||||
|
|
||||||
|
#include "backends/x11/meta-backend-x11.h"
|
||||||
|
|
||||||
|
struct _MetaCursorRendererX11Nested
|
||||||
|
{
|
||||||
|
MetaCursorRenderer parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_cursor_renderer_x11_nested_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (MetaCursorRendererX11Nested, meta_cursor_renderer_x11_nested,
|
||||||
|
META_TYPE_CURSOR_RENDERER);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_cursor_renderer_x11_nested_update_cursor (MetaCursorRenderer *renderer,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
if (cursor_sprite)
|
||||||
|
meta_cursor_sprite_realize_texture (cursor_sprite);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Cursor
|
||||||
|
create_empty_cursor (Display *xdisplay)
|
||||||
|
{
|
||||||
|
XcursorImage *image;
|
||||||
|
XcursorPixel *pixels;
|
||||||
|
Cursor xcursor;
|
||||||
|
|
||||||
|
image = XcursorImageCreate (1, 1);
|
||||||
|
if (image == NULL)
|
||||||
|
return None;
|
||||||
|
|
||||||
|
image->xhot = 0;
|
||||||
|
image->yhot = 0;
|
||||||
|
|
||||||
|
pixels = image->pixels;
|
||||||
|
pixels[0] = 0;
|
||||||
|
|
||||||
|
xcursor = XcursorImageLoadCursor (xdisplay, image);
|
||||||
|
XcursorImageDestroy (image);
|
||||||
|
|
||||||
|
return xcursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_cursor_renderer_x11_nested_init (MetaCursorRendererX11Nested *x11_nested)
|
||||||
|
{
|
||||||
|
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
||||||
|
Window xwindow = meta_backend_x11_get_xwindow (backend);
|
||||||
|
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
|
||||||
|
|
||||||
|
Cursor empty_xcursor = create_empty_cursor (xdisplay);
|
||||||
|
XDefineCursor (xdisplay, xwindow, empty_xcursor);
|
||||||
|
XFreeCursor (xdisplay, empty_xcursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_cursor_renderer_x11_nested_class_init (MetaCursorRendererX11NestedClass *klass)
|
||||||
|
{
|
||||||
|
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_CLASS (klass);
|
||||||
|
|
||||||
|
renderer_class->update_cursor = meta_cursor_renderer_x11_nested_update_cursor;
|
||||||
|
}
|
38
src/backends/x11/nested/meta-cursor-renderer-x11-nested.h
Normal file
38
src/backends/x11/nested/meta-cursor-renderer-x11-nested.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* -*- 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_CURSOR_RENDERER_X11_NESTED_NESTED_H
|
||||||
|
#define META_CURSOR_RENDERER_X11_NESTED_NESTED_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "backends/meta-cursor-renderer.h"
|
||||||
|
|
||||||
|
#define META_TYPE_CURSOR_RENDERER_X11_NESTED (meta_cursor_renderer_x11_nested_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaCursorRendererX11Nested,
|
||||||
|
meta_cursor_renderer_x11_nested,
|
||||||
|
META, CURSOR_RENDERER_X11_NESTED,
|
||||||
|
MetaCursorRenderer);
|
||||||
|
|
||||||
|
#endif /* META_CURSOR_RENDERER_X11_NESTED_NESTED_H */
|
@@ -15,7 +15,8 @@ struct _MetaCompositor
|
|||||||
{
|
{
|
||||||
MetaDisplay *display;
|
MetaDisplay *display;
|
||||||
|
|
||||||
guint repaint_func_id;
|
guint pre_paint_func_id;
|
||||||
|
guint post_paint_func_id;
|
||||||
|
|
||||||
gint64 server_time_query_time;
|
gint64 server_time_query_time;
|
||||||
gint64 server_time_offset;
|
gint64 server_time_offset;
|
||||||
@@ -40,6 +41,7 @@ struct _MetaCompositor
|
|||||||
MetaPluginManager *plugin_mgr;
|
MetaPluginManager *plugin_mgr;
|
||||||
|
|
||||||
gboolean frame_has_updated_xsurfaces;
|
gboolean frame_has_updated_xsurfaces;
|
||||||
|
gboolean have_x11_sync_object;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Wait 2ms after vblank before starting to draw next frame */
|
/* Wait 2ms after vblank before starting to draw next frame */
|
||||||
|
@@ -74,6 +74,7 @@
|
|||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include <X11/extensions/shape.h>
|
#include <X11/extensions/shape.h>
|
||||||
#include <X11/extensions/Xcomposite.h>
|
#include <X11/extensions/Xcomposite.h>
|
||||||
|
#include "meta-sync-ring.h"
|
||||||
|
|
||||||
#include "backends/x11/meta-backend-x11.h"
|
#include "backends/x11/meta-backend-x11.h"
|
||||||
|
|
||||||
@@ -120,7 +121,11 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
|
|||||||
void
|
void
|
||||||
meta_compositor_destroy (MetaCompositor *compositor)
|
meta_compositor_destroy (MetaCompositor *compositor)
|
||||||
{
|
{
|
||||||
clutter_threads_remove_repaint_func (compositor->repaint_func_id);
|
clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
|
||||||
|
clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
|
||||||
|
|
||||||
|
if (compositor->have_x11_sync_object)
|
||||||
|
meta_sync_ring_destroy ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -463,13 +468,11 @@ meta_compositor_manage (MetaCompositor *compositor)
|
|||||||
MetaDisplay *display = compositor->display;
|
MetaDisplay *display = compositor->display;
|
||||||
Display *xdisplay = display->xdisplay;
|
Display *xdisplay = display->xdisplay;
|
||||||
MetaScreen *screen = display->screen;
|
MetaScreen *screen = display->screen;
|
||||||
|
MetaBackend *backend = meta_get_backend ();
|
||||||
|
|
||||||
meta_screen_set_cm_selection (display->screen);
|
meta_screen_set_cm_selection (display->screen);
|
||||||
|
|
||||||
{
|
compositor->stage = meta_backend_get_stage (backend);
|
||||||
MetaBackend *backend = meta_get_backend ();
|
|
||||||
compositor->stage = meta_backend_get_stage (backend);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We use connect_after() here to accomodate code in GNOME Shell that,
|
/* We use connect_after() here to accomodate code in GNOME Shell that,
|
||||||
* when benchmarking drawing performance, connects to ::after-paint
|
* when benchmarking drawing performance, connects to ::after-paint
|
||||||
@@ -505,7 +508,7 @@ meta_compositor_manage (MetaCompositor *compositor)
|
|||||||
|
|
||||||
compositor->output = screen->composite_overlay_window;
|
compositor->output = screen->composite_overlay_window;
|
||||||
|
|
||||||
xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (meta_get_backend ()));
|
xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
|
||||||
|
|
||||||
XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
|
XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
|
||||||
|
|
||||||
@@ -525,6 +528,8 @@ meta_compositor_manage (MetaCompositor *compositor)
|
|||||||
* contents until we show the stage.
|
* contents until we show the stage.
|
||||||
*/
|
*/
|
||||||
XMapWindow (xdisplay, compositor->output);
|
XMapWindow (xdisplay, compositor->output);
|
||||||
|
|
||||||
|
compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect_windows (display->screen);
|
redirect_windows (display->screen);
|
||||||
@@ -726,6 +731,9 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
|||||||
process_damage (compositor, (XDamageNotifyEvent *) event, window);
|
process_damage (compositor, (XDamageNotifyEvent *) event, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compositor->have_x11_sync_object)
|
||||||
|
meta_sync_ring_handle_event (event);
|
||||||
|
|
||||||
/* Clutter needs to know about MapNotify events otherwise it will
|
/* Clutter needs to know about MapNotify events otherwise it will
|
||||||
think the stage is invisible */
|
think the stage is invisible */
|
||||||
if (!meta_is_wayland_compositor () && event->type == MapNotify)
|
if (!meta_is_wayland_compositor () && event->type == MapNotify)
|
||||||
@@ -1030,11 +1038,12 @@ frame_callback (CoglOnscreen *onscreen,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
pre_paint_windows (MetaCompositor *compositor)
|
meta_pre_paint_func (gpointer data)
|
||||||
{
|
{
|
||||||
GList *l;
|
GList *l;
|
||||||
MetaWindowActor *top_window;
|
MetaWindowActor *top_window;
|
||||||
|
MetaCompositor *compositor = data;
|
||||||
|
|
||||||
if (compositor->onscreen == NULL)
|
if (compositor->onscreen == NULL)
|
||||||
{
|
{
|
||||||
@@ -1046,7 +1055,7 @@ pre_paint_windows (MetaCompositor *compositor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (compositor->windows == NULL)
|
if (compositor->windows == NULL)
|
||||||
return;
|
return TRUE;
|
||||||
|
|
||||||
top_window = g_list_last (compositor->windows)->data;
|
top_window = g_list_last (compositor->windows)->data;
|
||||||
|
|
||||||
@@ -1063,10 +1072,12 @@ pre_paint_windows (MetaCompositor *compositor)
|
|||||||
{
|
{
|
||||||
/* We need to make sure that any X drawing that happens before
|
/* We need to make sure that any X drawing that happens before
|
||||||
* the XDamageSubtract() for each window above is visible to
|
* the XDamageSubtract() for each window above is visible to
|
||||||
* subsequent GL rendering; the only standardized way to do this
|
* subsequent GL rendering; the standardized way to do this is
|
||||||
* is EXT_x11_sync_object, which isn't yet widely available. For
|
* GL_EXT_X11_sync_object. Since this isn't implemented yet in
|
||||||
* now, we count on details of Xorg and the open source drivers,
|
* mesa, we also have a path that relies on the implementation
|
||||||
* and hope for the best otherwise.
|
* of the open source drivers.
|
||||||
|
*
|
||||||
|
* Anything else, we just hope for the best.
|
||||||
*
|
*
|
||||||
* Xorg and open source driver specifics:
|
* Xorg and open source driver specifics:
|
||||||
*
|
*
|
||||||
@@ -1081,17 +1092,28 @@ pre_paint_windows (MetaCompositor *compositor)
|
|||||||
* round trip request at this point is sufficient to flush the
|
* round trip request at this point is sufficient to flush the
|
||||||
* GLX buffers.
|
* GLX buffers.
|
||||||
*/
|
*/
|
||||||
XSync (compositor->display->xdisplay, False);
|
if (compositor->have_x11_sync_object)
|
||||||
|
compositor->have_x11_sync_object = meta_sync_ring_insert_wait ();
|
||||||
compositor->frame_has_updated_xsurfaces = FALSE;
|
else
|
||||||
|
XSync (compositor->display->xdisplay, False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_repaint_func (gpointer data)
|
meta_post_paint_func (gpointer data)
|
||||||
{
|
{
|
||||||
MetaCompositor *compositor = data;
|
MetaCompositor *compositor = data;
|
||||||
pre_paint_windows (compositor);
|
|
||||||
|
if (compositor->frame_has_updated_xsurfaces)
|
||||||
|
{
|
||||||
|
if (compositor->have_x11_sync_object)
|
||||||
|
compositor->have_x11_sync_object = meta_sync_ring_after_frame ();
|
||||||
|
|
||||||
|
compositor->frame_has_updated_xsurfaces = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,10 +1148,16 @@ meta_compositor_new (MetaDisplay *display)
|
|||||||
G_CALLBACK (on_shadow_factory_changed),
|
G_CALLBACK (on_shadow_factory_changed),
|
||||||
compositor);
|
compositor);
|
||||||
|
|
||||||
compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
|
compositor->pre_paint_func_id =
|
||||||
compositor,
|
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
|
||||||
NULL);
|
meta_pre_paint_func,
|
||||||
|
compositor,
|
||||||
|
NULL);
|
||||||
|
compositor->post_paint_func_id =
|
||||||
|
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
|
||||||
|
meta_post_paint_func,
|
||||||
|
compositor,
|
||||||
|
NULL);
|
||||||
return compositor;
|
return compositor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,6 +22,8 @@
|
|||||||
#include "meta-background-private.h"
|
#include "meta-background-private.h"
|
||||||
#include "cogl-utils.h"
|
#include "cogl-utils.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
CHANGED,
|
CHANGED,
|
||||||
@@ -71,6 +73,8 @@ enum
|
|||||||
|
|
||||||
G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static gboolean texture_has_alpha (CoglTexture *texture);
|
||||||
|
|
||||||
static GSList *all_backgrounds = NULL;
|
static GSList *all_backgrounds = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -474,7 +478,7 @@ get_texture_area (MetaBackground *self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
draw_texture (MetaBackground *self,
|
draw_texture (MetaBackground *self,
|
||||||
CoglFramebuffer *framebuffer,
|
CoglFramebuffer *framebuffer,
|
||||||
CoglPipeline *pipeline,
|
CoglPipeline *pipeline,
|
||||||
@@ -483,6 +487,7 @@ draw_texture (MetaBackground *self,
|
|||||||
{
|
{
|
||||||
MetaBackgroundPrivate *priv = self->priv;
|
MetaBackgroundPrivate *priv = self->priv;
|
||||||
cairo_rectangle_int_t texture_area;
|
cairo_rectangle_int_t texture_area;
|
||||||
|
gboolean bare_region_visible;
|
||||||
|
|
||||||
get_texture_area (self, monitor_area, texture, &texture_area);
|
get_texture_area (self, monitor_area, texture, &texture_area);
|
||||||
|
|
||||||
@@ -503,6 +508,9 @@ draw_texture (MetaBackground *self,
|
|||||||
- texture_area.y / (float)texture_area.height,
|
- texture_area.y / (float)texture_area.height,
|
||||||
(monitor_area->width - texture_area.x) / (float)texture_area.width,
|
(monitor_area->width - texture_area.x) / (float)texture_area.width,
|
||||||
(monitor_area->height - texture_area.y) / (float)texture_area.height);
|
(monitor_area->height - texture_area.y) / (float)texture_area.height);
|
||||||
|
|
||||||
|
bare_region_visible = texture_has_alpha (texture);
|
||||||
|
|
||||||
/* Draw just the texture */
|
/* Draw just the texture */
|
||||||
break;
|
break;
|
||||||
case G_DESKTOP_BACKGROUND_STYLE_CENTERED:
|
case G_DESKTOP_BACKGROUND_STYLE_CENTERED:
|
||||||
@@ -513,11 +521,16 @@ draw_texture (MetaBackground *self,
|
|||||||
texture_area.x + texture_area.width,
|
texture_area.x + texture_area.width,
|
||||||
texture_area.y + texture_area.height,
|
texture_area.y + texture_area.height,
|
||||||
0, 0, 1.0, 1.0);
|
0, 0, 1.0, 1.0);
|
||||||
|
bare_region_visible = texture_has_alpha (texture) || memcmp (&texture_area, monitor_area, sizeof (cairo_rectangle_int_t)) != 0;
|
||||||
|
break;
|
||||||
case G_DESKTOP_BACKGROUND_STYLE_NONE:
|
case G_DESKTOP_BACKGROUND_STYLE_NONE:
|
||||||
|
bare_region_visible = TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_return_if_reached();
|
g_return_val_if_reached(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bare_region_visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -748,6 +761,7 @@ meta_background_get_texture (MetaBackground *self,
|
|||||||
if (monitor->dirty)
|
if (monitor->dirty)
|
||||||
{
|
{
|
||||||
CoglError *catch_error = NULL;
|
CoglError *catch_error = NULL;
|
||||||
|
gboolean bare_region_visible = FALSE;
|
||||||
|
|
||||||
if (monitor->texture == NULL)
|
if (monitor->texture == NULL)
|
||||||
{
|
{
|
||||||
@@ -783,9 +797,9 @@ meta_background_get_texture (MetaBackground *self,
|
|||||||
cogl_pipeline_set_layer_texture (pipeline, 0, texture2);
|
cogl_pipeline_set_layer_texture (pipeline, 0, texture2);
|
||||||
cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (priv->style));
|
cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (priv->style));
|
||||||
|
|
||||||
draw_texture (self,
|
bare_region_visible = draw_texture (self,
|
||||||
monitor->fbo, pipeline,
|
monitor->fbo, pipeline,
|
||||||
texture2, &monitor_area);
|
texture2, &monitor_area);
|
||||||
|
|
||||||
cogl_object_unref (pipeline);
|
cogl_object_unref (pipeline);
|
||||||
}
|
}
|
||||||
@@ -796,8 +810,7 @@ meta_background_get_texture (MetaBackground *self,
|
|||||||
0.0, 0.0, 0.0, 0.0);
|
0.0, 0.0, 0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture1 != NULL &&
|
if (texture1 != NULL && priv->blend_factor != 1.0)
|
||||||
!(texture2 != NULL && priv->blend_factor == 1.0 && !texture_has_alpha (texture2)))
|
|
||||||
{
|
{
|
||||||
CoglPipeline *pipeline = create_pipeline (PIPELINE_ADD);
|
CoglPipeline *pipeline = create_pipeline (PIPELINE_ADD);
|
||||||
cogl_pipeline_set_color4f (pipeline,
|
cogl_pipeline_set_color4f (pipeline,
|
||||||
@@ -808,15 +821,14 @@ meta_background_get_texture (MetaBackground *self,
|
|||||||
cogl_pipeline_set_layer_texture (pipeline, 0, texture1);
|
cogl_pipeline_set_layer_texture (pipeline, 0, texture1);
|
||||||
cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (priv->style));
|
cogl_pipeline_set_layer_wrap_mode (pipeline, 0, get_wrap_mode (priv->style));
|
||||||
|
|
||||||
draw_texture (self,
|
bare_region_visible = bare_region_visible || draw_texture (self,
|
||||||
monitor->fbo, pipeline,
|
monitor->fbo, pipeline,
|
||||||
texture1, &monitor_area);
|
texture1, &monitor_area);
|
||||||
|
|
||||||
cogl_object_unref (pipeline);
|
cogl_object_unref (pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((texture2 != NULL && priv->blend_factor == 1.0 && !texture_has_alpha (texture2)) ||
|
if (bare_region_visible)
|
||||||
(texture1 != NULL && !texture_has_alpha (texture1))))
|
|
||||||
{
|
{
|
||||||
CoglPipeline *pipeline = create_pipeline (PIPELINE_OVER_REVERSE);
|
CoglPipeline *pipeline = create_pipeline (PIPELINE_OVER_REVERSE);
|
||||||
|
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
struct _MetaSurfaceActorWaylandPrivate
|
struct _MetaSurfaceActorWaylandPrivate
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *surface;
|
MetaWaylandSurface *surface;
|
||||||
|
struct wl_list frame_callback_list;
|
||||||
};
|
};
|
||||||
typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate;
|
typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate;
|
||||||
|
|
||||||
@@ -197,6 +198,10 @@ meta_surface_actor_wayland_sync_state (MetaSurfaceActorWayland *self)
|
|||||||
scaled_input_region);
|
scaled_input_region);
|
||||||
cairo_region_destroy (scaled_input_region);
|
cairo_region_destroy (scaled_input_region);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta_surface_actor_set_input_region (META_SURFACE_ACTOR (self), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Opaque region */
|
/* Opaque region */
|
||||||
if (surface->opaque_region)
|
if (surface->opaque_region)
|
||||||
@@ -212,6 +217,10 @@ meta_surface_actor_wayland_sync_state (MetaSurfaceActorWayland *self)
|
|||||||
scaled_opaque_region);
|
scaled_opaque_region);
|
||||||
cairo_region_destroy (scaled_opaque_region);
|
cairo_region_destroy (scaled_opaque_region);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta_surface_actor_set_opaque_region (META_SURFACE_ACTOR (self), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
meta_surface_actor_wayland_sync_subsurface_state (self);
|
meta_surface_actor_wayland_sync_subsurface_state (self);
|
||||||
}
|
}
|
||||||
@@ -271,12 +280,25 @@ meta_surface_actor_wayland_is_on_monitor (MetaSurfaceActorWayland *self,
|
|||||||
return is_on_monitor;
|
return is_on_monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self,
|
||||||
|
struct wl_list *frame_callbacks)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||||
|
|
||||||
|
wl_list_insert_list (&priv->frame_callback_list, frame_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
static MetaWindow *
|
static MetaWindow *
|
||||||
meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
|
meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
|
||||||
{
|
{
|
||||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (META_SURFACE_ACTOR_WAYLAND (actor));
|
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (META_SURFACE_ACTOR_WAYLAND (actor));
|
||||||
|
MetaWaylandSurface *surface = priv->surface;
|
||||||
|
|
||||||
return priv->surface->window;
|
if (!surface)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return surface->window;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -323,7 +345,13 @@ meta_surface_actor_wayland_paint (ClutterActor *actor)
|
|||||||
meta_surface_actor_wayland_get_instance_private (self);
|
meta_surface_actor_wayland_get_instance_private (self);
|
||||||
|
|
||||||
if (priv->surface)
|
if (priv->surface)
|
||||||
meta_wayland_surface_update_outputs (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);
|
||||||
|
}
|
||||||
|
|
||||||
CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
|
CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
|
||||||
}
|
}
|
||||||
@@ -375,6 +403,7 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
|
|||||||
|
|
||||||
g_assert (meta_is_wayland_compositor ());
|
g_assert (meta_is_wayland_compositor ());
|
||||||
|
|
||||||
|
wl_list_init (&priv->frame_callback_list);
|
||||||
priv->surface = surface;
|
priv->surface = surface;
|
||||||
|
|
||||||
return META_SURFACE_ACTOR (self);
|
return META_SURFACE_ACTOR (self);
|
||||||
@@ -398,8 +427,14 @@ meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self)
|
|||||||
void
|
void
|
||||||
meta_surface_actor_wayland_surface_destroyed (MetaSurfaceActorWayland *self)
|
meta_surface_actor_wayland_surface_destroyed (MetaSurfaceActorWayland *self)
|
||||||
{
|
{
|
||||||
|
MetaWaylandFrameCallback *callback, *next;
|
||||||
MetaSurfaceActorWaylandPrivate *priv =
|
MetaSurfaceActorWaylandPrivate *priv =
|
||||||
meta_surface_actor_wayland_get_instance_private (self);
|
meta_surface_actor_wayland_get_instance_private (self);
|
||||||
|
|
||||||
|
wl_list_for_each_safe (callback, next, &priv->frame_callback_list, link)
|
||||||
|
{
|
||||||
|
wl_resource_destroy (callback->resource);
|
||||||
|
}
|
||||||
|
|
||||||
priv->surface = NULL;
|
priv->surface = NULL;
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "meta-surface-actor.h"
|
#include "meta-surface-actor.h"
|
||||||
|
|
||||||
#include "wayland/meta-wayland.h"
|
#include "wayland/meta-wayland.h"
|
||||||
|
#include "wayland/meta-wayland-private.h"
|
||||||
|
|
||||||
#include "backends/meta-monitor-manager-private.h"
|
#include "backends/meta-monitor-manager-private.h"
|
||||||
|
|
||||||
@@ -78,6 +79,9 @@ void meta_surface_actor_wayland_sync_subsurface_state (MetaSurfaceActorWayland *
|
|||||||
gboolean meta_surface_actor_wayland_is_on_monitor (MetaSurfaceActorWayland *self,
|
gboolean meta_surface_actor_wayland_is_on_monitor (MetaSurfaceActorWayland *self,
|
||||||
MetaMonitorInfo *monitor);
|
MetaMonitorInfo *monitor);
|
||||||
|
|
||||||
|
void meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self,
|
||||||
|
struct wl_list *frame_callbacks);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */
|
#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */
|
||||||
|
592
src/compositor/meta-sync-ring.c
Normal file
592
src/compositor/meta-sync-ring.c
Normal file
@@ -0,0 +1,592 @@
|
|||||||
|
/*
|
||||||
|
* This is based on an original C++ implementation for compiz that
|
||||||
|
* carries the following copyright notice:
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright © 2011 NVIDIA 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 NVIDIA
|
||||||
|
* Corporation not be used in advertising or publicity pertaining to
|
||||||
|
* distribution of the software without specific, written prior
|
||||||
|
* permission. NVIDIA Corporation makes no representations about the
|
||||||
|
* suitability of this software for any purpose. It is provided "as
|
||||||
|
* is" without express or implied warranty.
|
||||||
|
*
|
||||||
|
* NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION 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.
|
||||||
|
*
|
||||||
|
* Authors: James Jones <jajones@nvidia.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <X11/extensions/sync.h>
|
||||||
|
|
||||||
|
#include <cogl/cogl.h>
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
|
||||||
|
#include <meta/util.h>
|
||||||
|
|
||||||
|
#include "meta-sync-ring.h"
|
||||||
|
|
||||||
|
/* Theory of operation:
|
||||||
|
*
|
||||||
|
* We use a ring of NUM_SYNCS fence objects. On each frame we advance
|
||||||
|
* to the next fence in the ring. For each fence we do:
|
||||||
|
*
|
||||||
|
* 1. fence is XSyncTriggerFence()'d and glWaitSync()'d
|
||||||
|
* 2. NUM_SYNCS / 2 frames later, fence should be triggered
|
||||||
|
* 3. fence is XSyncResetFence()'d
|
||||||
|
* 4. NUM_SYNCS / 2 frames later, fence should be reset
|
||||||
|
* 5. go back to 1 and re-use fence
|
||||||
|
*
|
||||||
|
* glClientWaitSync() and XAlarms are used in steps 2 and 4,
|
||||||
|
* respectively, to double-check the expectections.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NUM_SYNCS 10
|
||||||
|
#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */
|
||||||
|
#define MAX_REBOOT_ATTEMPTS 2
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
META_SYNC_STATE_READY,
|
||||||
|
META_SYNC_STATE_WAITING,
|
||||||
|
META_SYNC_STATE_DONE,
|
||||||
|
META_SYNC_STATE_RESET_PENDING,
|
||||||
|
} MetaSyncState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Display *xdisplay;
|
||||||
|
|
||||||
|
XSyncFence xfence;
|
||||||
|
GLsync gl_x11_sync;
|
||||||
|
GLsync gpu_fence;
|
||||||
|
|
||||||
|
XSyncCounter xcounter;
|
||||||
|
XSyncAlarm xalarm;
|
||||||
|
XSyncValue next_counter_value;
|
||||||
|
|
||||||
|
MetaSyncState state;
|
||||||
|
} MetaSync;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Display *xdisplay;
|
||||||
|
int xsync_event_base;
|
||||||
|
int xsync_error_base;
|
||||||
|
|
||||||
|
GHashTable *alarm_to_sync;
|
||||||
|
|
||||||
|
MetaSync *syncs_array[NUM_SYNCS];
|
||||||
|
guint current_sync_idx;
|
||||||
|
MetaSync *current_sync;
|
||||||
|
guint warmup_syncs;
|
||||||
|
|
||||||
|
guint reboots;
|
||||||
|
} MetaSyncRing;
|
||||||
|
|
||||||
|
static MetaSyncRing meta_sync_ring = { 0 };
|
||||||
|
|
||||||
|
static XSyncValue SYNC_VALUE_ZERO;
|
||||||
|
static XSyncValue SYNC_VALUE_ONE;
|
||||||
|
|
||||||
|
static const char* (*meta_gl_get_string) (GLenum name);
|
||||||
|
static void (*meta_gl_get_integerv) (GLenum pname,
|
||||||
|
GLint *params);
|
||||||
|
static const char* (*meta_gl_get_stringi) (GLenum name,
|
||||||
|
GLuint index);
|
||||||
|
static void (*meta_gl_delete_sync) (GLsync sync);
|
||||||
|
static GLenum (*meta_gl_client_wait_sync) (GLsync sync,
|
||||||
|
GLbitfield flags,
|
||||||
|
GLuint64 timeout);
|
||||||
|
static void (*meta_gl_wait_sync) (GLsync sync,
|
||||||
|
GLbitfield flags,
|
||||||
|
GLuint64 timeout);
|
||||||
|
static GLsync (*meta_gl_import_sync) (GLenum external_sync_type,
|
||||||
|
GLintptr external_sync,
|
||||||
|
GLbitfield flags);
|
||||||
|
static GLsync (*meta_gl_fence_sync) (GLenum condition,
|
||||||
|
GLbitfield flags);
|
||||||
|
|
||||||
|
static MetaSyncRing *
|
||||||
|
meta_sync_ring_get (void)
|
||||||
|
{
|
||||||
|
if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &meta_sync_ring;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
load_gl_symbol (const char *name,
|
||||||
|
void **func)
|
||||||
|
{
|
||||||
|
*func = cogl_get_proc_address (name);
|
||||||
|
if (!*func)
|
||||||
|
{
|
||||||
|
meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
check_gl_extensions (void)
|
||||||
|
{
|
||||||
|
ClutterBackend *backend;
|
||||||
|
CoglContext *cogl_context;
|
||||||
|
CoglDisplay *cogl_display;
|
||||||
|
CoglRenderer *cogl_renderer;
|
||||||
|
|
||||||
|
backend = clutter_get_default_backend ();
|
||||||
|
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||||
|
cogl_display = cogl_context_get_display (cogl_context);
|
||||||
|
cogl_renderer = cogl_display_get_renderer (cogl_display);
|
||||||
|
|
||||||
|
switch (cogl_renderer_get_driver (cogl_renderer))
|
||||||
|
{
|
||||||
|
case COGL_DRIVER_GL3:
|
||||||
|
{
|
||||||
|
int num_extensions, i;
|
||||||
|
gboolean arb_sync = FALSE;
|
||||||
|
gboolean x11_sync_object = FALSE;
|
||||||
|
|
||||||
|
meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions);
|
||||||
|
|
||||||
|
for (i = 0; i < num_extensions; ++i)
|
||||||
|
{
|
||||||
|
const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i);
|
||||||
|
|
||||||
|
if (g_strcmp0 ("GL_ARB_sync", ext) == 0)
|
||||||
|
arb_sync = TRUE;
|
||||||
|
else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0)
|
||||||
|
x11_sync_object = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arb_sync && x11_sync_object;
|
||||||
|
}
|
||||||
|
case COGL_DRIVER_GL:
|
||||||
|
{
|
||||||
|
const char *extensions = meta_gl_get_string (GL_EXTENSIONS);
|
||||||
|
return (extensions != NULL &&
|
||||||
|
strstr (extensions, "GL_ARB_sync") != NULL &&
|
||||||
|
strstr (extensions, "GL_EXT_x11_sync_object") != NULL);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
load_required_symbols (void)
|
||||||
|
{
|
||||||
|
static gboolean success = FALSE;
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* We don't link against libGL directly because cogl may want to
|
||||||
|
* use something else. This assumes that cogl has been initialized
|
||||||
|
* and dynamically loaded libGL at this point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string))
|
||||||
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv))
|
||||||
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!check_gl_extensions ())
|
||||||
|
{
|
||||||
|
meta_verbose ("MetaSyncRing: couldn't find required GL extensions\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync))
|
||||||
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync))
|
||||||
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync))
|
||||||
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
|
||||||
|
goto out;
|
||||||
|
if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
success = TRUE;
|
||||||
|
out:
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_sync_insert (MetaSync *self)
|
||||||
|
{
|
||||||
|
g_return_if_fail (self->state == META_SYNC_STATE_READY);
|
||||||
|
|
||||||
|
XSyncTriggerFence (self->xdisplay, self->xfence);
|
||||||
|
XFlush (self->xdisplay);
|
||||||
|
|
||||||
|
meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED);
|
||||||
|
self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
|
||||||
|
self->state = META_SYNC_STATE_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLenum
|
||||||
|
meta_sync_check_update_finished (MetaSync *self,
|
||||||
|
GLuint64 timeout)
|
||||||
|
{
|
||||||
|
GLenum status = GL_WAIT_FAILED;
|
||||||
|
|
||||||
|
switch (self->state)
|
||||||
|
{
|
||||||
|
case META_SYNC_STATE_DONE:
|
||||||
|
status = GL_ALREADY_SIGNALED;
|
||||||
|
break;
|
||||||
|
case META_SYNC_STATE_WAITING:
|
||||||
|
status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout);
|
||||||
|
if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
|
||||||
|
{
|
||||||
|
self->state = META_SYNC_STATE_DONE;
|
||||||
|
meta_gl_delete_sync (self->gpu_fence);
|
||||||
|
self->gpu_fence = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warn_if_fail (status != GL_WAIT_FAILED);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_sync_reset (MetaSync *self)
|
||||||
|
{
|
||||||
|
XSyncAlarmAttributes attrs;
|
||||||
|
int overflow;
|
||||||
|
|
||||||
|
g_return_if_fail (self->state == META_SYNC_STATE_DONE);
|
||||||
|
|
||||||
|
XSyncResetFence (self->xdisplay, self->xfence);
|
||||||
|
|
||||||
|
attrs.trigger.wait_value = self->next_counter_value;
|
||||||
|
|
||||||
|
XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs);
|
||||||
|
XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value);
|
||||||
|
|
||||||
|
XSyncValueAdd (&self->next_counter_value,
|
||||||
|
self->next_counter_value,
|
||||||
|
SYNC_VALUE_ONE,
|
||||||
|
&overflow);
|
||||||
|
|
||||||
|
self->state = META_SYNC_STATE_RESET_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_sync_handle_event (MetaSync *self,
|
||||||
|
XSyncAlarmNotifyEvent *event)
|
||||||
|
{
|
||||||
|
g_return_if_fail (event->alarm == self->xalarm);
|
||||||
|
g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING);
|
||||||
|
|
||||||
|
self->state = META_SYNC_STATE_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaSync *
|
||||||
|
meta_sync_new (Display *xdisplay)
|
||||||
|
{
|
||||||
|
MetaSync *self;
|
||||||
|
XSyncAlarmAttributes attrs;
|
||||||
|
|
||||||
|
self = g_malloc0 (sizeof (MetaSync));
|
||||||
|
|
||||||
|
self->xdisplay = xdisplay;
|
||||||
|
|
||||||
|
self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
|
||||||
|
self->gl_x11_sync = 0;
|
||||||
|
self->gpu_fence = 0;
|
||||||
|
|
||||||
|
self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
|
||||||
|
|
||||||
|
attrs.trigger.counter = self->xcounter;
|
||||||
|
attrs.trigger.value_type = XSyncAbsolute;
|
||||||
|
attrs.trigger.wait_value = SYNC_VALUE_ONE;
|
||||||
|
attrs.trigger.test_type = XSyncPositiveTransition;
|
||||||
|
attrs.events = TRUE;
|
||||||
|
self->xalarm = XSyncCreateAlarm (xdisplay,
|
||||||
|
XSyncCACounter |
|
||||||
|
XSyncCAValueType |
|
||||||
|
XSyncCAValue |
|
||||||
|
XSyncCATestType |
|
||||||
|
XSyncCAEvents,
|
||||||
|
&attrs);
|
||||||
|
|
||||||
|
XSyncIntToValue (&self->next_counter_value, 1);
|
||||||
|
|
||||||
|
self->state = META_SYNC_STATE_READY;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_sync_import (MetaSync *self)
|
||||||
|
{
|
||||||
|
g_return_if_fail (self->gl_x11_sync == 0);
|
||||||
|
self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
alarm_event_predicate (Display *dpy,
|
||||||
|
XEvent *event,
|
||||||
|
XPointer data)
|
||||||
|
{
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
if (event->type == ring->xsync_event_base + XSyncAlarmNotify)
|
||||||
|
{
|
||||||
|
if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm)
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_sync_free (MetaSync *self)
|
||||||
|
{
|
||||||
|
/* When our assumptions don't hold, something has gone wrong but we
|
||||||
|
* don't know what, so we reboot the ring. While doing that, we
|
||||||
|
* trigger fences before deleting them to try to get ourselves out
|
||||||
|
* of a potentially stuck GPU state.
|
||||||
|
*/
|
||||||
|
switch (self->state)
|
||||||
|
{
|
||||||
|
case META_SYNC_STATE_WAITING:
|
||||||
|
meta_gl_delete_sync (self->gpu_fence);
|
||||||
|
break;
|
||||||
|
case META_SYNC_STATE_DONE:
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
|
case META_SYNC_STATE_RESET_PENDING:
|
||||||
|
{
|
||||||
|
XEvent event;
|
||||||
|
XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self);
|
||||||
|
meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event);
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case META_SYNC_STATE_READY:
|
||||||
|
XSyncTriggerFence (self->xdisplay, self->xfence);
|
||||||
|
XFlush (self->xdisplay);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_gl_delete_sync (self->gl_x11_sync);
|
||||||
|
XSyncDestroyFence (self->xdisplay, self->xfence);
|
||||||
|
XSyncDestroyCounter (self->xdisplay, self->xcounter);
|
||||||
|
XSyncDestroyAlarm (self->xdisplay, self->xalarm);
|
||||||
|
|
||||||
|
g_free (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_sync_ring_init (Display *xdisplay)
|
||||||
|
{
|
||||||
|
gint major, minor;
|
||||||
|
guint i;
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail (xdisplay != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (ring->xdisplay == NULL, FALSE);
|
||||||
|
|
||||||
|
if (!load_required_symbols ())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) ||
|
||||||
|
!XSyncInitialize (xdisplay, &major, &minor))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
XSyncIntToValue (&SYNC_VALUE_ZERO, 0);
|
||||||
|
XSyncIntToValue (&SYNC_VALUE_ONE, 1);
|
||||||
|
|
||||||
|
ring->xdisplay = xdisplay;
|
||||||
|
|
||||||
|
ring->alarm_to_sync = g_hash_table_new (NULL, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SYNCS; ++i)
|
||||||
|
{
|
||||||
|
MetaSync *sync = meta_sync_new (ring->xdisplay);
|
||||||
|
ring->syncs_array[i] = sync;
|
||||||
|
g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
|
||||||
|
}
|
||||||
|
/* Since the connection we create the X fences on isn't the same as
|
||||||
|
* the one used for the GLX context, we need to XSync() here to
|
||||||
|
* ensure glImportSync() succeeds. */
|
||||||
|
XSync (xdisplay, False);
|
||||||
|
for (i = 0; i < NUM_SYNCS; ++i)
|
||||||
|
meta_sync_import (ring->syncs_array[i]);
|
||||||
|
|
||||||
|
ring->current_sync_idx = 0;
|
||||||
|
ring->current_sync = ring->syncs_array[0];
|
||||||
|
ring->warmup_syncs = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_sync_ring_destroy (void)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_return_if_fail (ring->xdisplay != NULL);
|
||||||
|
|
||||||
|
ring->current_sync_idx = 0;
|
||||||
|
ring->current_sync = NULL;
|
||||||
|
ring->warmup_syncs = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SYNCS; ++i)
|
||||||
|
meta_sync_free (ring->syncs_array[i]);
|
||||||
|
|
||||||
|
g_hash_table_destroy (ring->alarm_to_sync);
|
||||||
|
|
||||||
|
ring->xsync_event_base = 0;
|
||||||
|
ring->xsync_error_base = 0;
|
||||||
|
ring->xdisplay = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_sync_ring_reboot (Display *xdisplay)
|
||||||
|
{
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
meta_sync_ring_destroy ();
|
||||||
|
|
||||||
|
ring->reboots += 1;
|
||||||
|
|
||||||
|
if (!meta_sync_ring_get ())
|
||||||
|
{
|
||||||
|
meta_warning ("MetaSyncRing: Too many reboots -- disabling\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return meta_sync_ring_init (xdisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_sync_ring_after_frame (void)
|
||||||
|
{
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
|
||||||
|
|
||||||
|
if (ring->warmup_syncs >= NUM_SYNCS / 2)
|
||||||
|
{
|
||||||
|
guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS;
|
||||||
|
MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx];
|
||||||
|
|
||||||
|
GLenum status = meta_sync_check_update_finished (sync_to_reset, 0);
|
||||||
|
if (status == GL_TIMEOUT_EXPIRED)
|
||||||
|
{
|
||||||
|
meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n");
|
||||||
|
status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
|
||||||
|
{
|
||||||
|
meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n");
|
||||||
|
return meta_sync_ring_reboot (ring->xdisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_sync_reset (sync_to_reset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ring->warmup_syncs += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring->current_sync_idx += 1;
|
||||||
|
ring->current_sync_idx %= NUM_SYNCS;
|
||||||
|
|
||||||
|
ring->current_sync = ring->syncs_array[ring->current_sync_idx];
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_sync_ring_insert_wait (void)
|
||||||
|
{
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
|
||||||
|
|
||||||
|
if (ring->current_sync->state != META_SYNC_STATE_READY)
|
||||||
|
{
|
||||||
|
meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n");
|
||||||
|
if (!meta_sync_ring_reboot (ring->xdisplay))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_sync_insert (ring->current_sync);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_sync_ring_handle_event (XEvent *xevent)
|
||||||
|
{
|
||||||
|
XSyncAlarmNotifyEvent *event;
|
||||||
|
MetaSync *sync;
|
||||||
|
MetaSyncRing *ring = meta_sync_ring_get ();
|
||||||
|
|
||||||
|
if (!ring)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_return_if_fail (ring->xdisplay != NULL);
|
||||||
|
|
||||||
|
if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify))
|
||||||
|
return;
|
||||||
|
|
||||||
|
event = (XSyncAlarmNotifyEvent *) xevent;
|
||||||
|
|
||||||
|
sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm);
|
||||||
|
if (sync)
|
||||||
|
meta_sync_handle_event (sync, event);
|
||||||
|
}
|
14
src/compositor/meta-sync-ring.h
Normal file
14
src/compositor/meta-sync-ring.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef _META_SYNC_RING_H_
|
||||||
|
#define _META_SYNC_RING_H_
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
gboolean meta_sync_ring_init (Display *dpy);
|
||||||
|
void meta_sync_ring_destroy (void);
|
||||||
|
gboolean meta_sync_ring_after_frame (void);
|
||||||
|
gboolean meta_sync_ring_insert_wait (void);
|
||||||
|
void meta_sync_ring_handle_event (XEvent *event);
|
||||||
|
|
||||||
|
#endif /* _META_SYNC_RING_H_ */
|
@@ -493,11 +493,10 @@ place_window_if_needed(MetaWindow *window,
|
|||||||
if (window->placed || did_placement)
|
if (window->placed || did_placement)
|
||||||
{
|
{
|
||||||
if (window->maximize_horizontally_after_placement ||
|
if (window->maximize_horizontally_after_placement ||
|
||||||
window->maximize_vertically_after_placement ||
|
window->maximize_vertically_after_placement)
|
||||||
window->fullscreen_after_placement)
|
|
||||||
{
|
{
|
||||||
/* define a sane saved_rect so that the user can unmaximize or
|
/* define a sane saved_rect so that the user can unmaximize to
|
||||||
* make unfullscreen to something reasonable.
|
* something reasonable.
|
||||||
*/
|
*/
|
||||||
if (info->current.width >= info->work_area_monitor.width)
|
if (info->current.width >= info->work_area_monitor.width)
|
||||||
{
|
{
|
||||||
@@ -525,15 +524,6 @@ place_window_if_needed(MetaWindow *window,
|
|||||||
(window->maximize_vertically_after_placement ?
|
(window->maximize_vertically_after_placement ?
|
||||||
META_MAXIMIZE_VERTICAL : 0), &info->current);
|
META_MAXIMIZE_VERTICAL : 0), &info->current);
|
||||||
|
|
||||||
if (window->fullscreen_after_placement)
|
|
||||||
{
|
|
||||||
window->saved_rect = info->current;
|
|
||||||
window->fullscreen = TRUE;
|
|
||||||
window->fullscreen_after_placement = FALSE;
|
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (window), "fullscreen");
|
|
||||||
}
|
|
||||||
|
|
||||||
window->maximize_horizontally_after_placement = FALSE;
|
window->maximize_horizontally_after_placement = FALSE;
|
||||||
window->maximize_vertically_after_placement = FALSE;
|
window->maximize_vertically_after_placement = FALSE;
|
||||||
}
|
}
|
||||||
|
@@ -152,6 +152,10 @@ const MetaMonitorInfo* meta_screen_get_monitor_for_rect (MetaScreen *screen
|
|||||||
const MetaMonitorInfo* meta_screen_calculate_monitor_for_window (MetaScreen *screen,
|
const MetaMonitorInfo* meta_screen_calculate_monitor_for_window (MetaScreen *screen,
|
||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
|
|
||||||
|
const MetaMonitorInfo* meta_screen_get_monitor_for_point (MetaScreen *screen,
|
||||||
|
int x,
|
||||||
|
int y);
|
||||||
|
|
||||||
|
|
||||||
const MetaMonitorInfo* meta_screen_get_monitor_neighbor (MetaScreen *screen,
|
const MetaMonitorInfo* meta_screen_get_monitor_neighbor (MetaScreen *screen,
|
||||||
int which_monitor,
|
int which_monitor,
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
#include <meta/meta-enum-types.h>
|
#include <meta/meta-enum-types.h>
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "meta-cursor-tracker-private.h"
|
#include "meta-cursor-tracker-private.h"
|
||||||
|
#include "boxes-private.h"
|
||||||
|
|
||||||
#include <X11/extensions/Xinerama.h>
|
#include <X11/extensions/Xinerama.h>
|
||||||
#include <X11/extensions/Xcomposite.h>
|
#include <X11/extensions/Xcomposite.h>
|
||||||
@@ -1255,21 +1256,47 @@ update_num_workspaces (MetaScreen *screen,
|
|||||||
g_object_notify (G_OBJECT (screen), "n-workspaces");
|
g_object_notify (G_OBJECT (screen), "n-workspaces");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
root_cursor_prepare_at (MetaCursorSprite *cursor_sprite,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
MetaScreen *screen)
|
||||||
|
{
|
||||||
|
const MetaMonitorInfo *monitor;
|
||||||
|
|
||||||
|
monitor = meta_screen_get_monitor_for_point (screen, x, y);
|
||||||
|
|
||||||
|
/* Reload the cursor texture if the scale has changed. */
|
||||||
|
meta_cursor_sprite_set_theme_scale (cursor_sprite, monitor->scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
manage_root_cursor_sprite_scale (MetaScreen *screen,
|
||||||
|
MetaCursorSprite *cursor_sprite)
|
||||||
|
{
|
||||||
|
g_signal_connect_object (cursor_sprite,
|
||||||
|
"prepare-at",
|
||||||
|
G_CALLBACK (root_cursor_prepare_at),
|
||||||
|
screen,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_screen_update_cursor (MetaScreen *screen)
|
meta_screen_update_cursor (MetaScreen *screen)
|
||||||
{
|
{
|
||||||
MetaDisplay *display = screen->display;
|
MetaDisplay *display = screen->display;
|
||||||
MetaCursor cursor = screen->current_cursor;
|
MetaCursor cursor = screen->current_cursor;
|
||||||
Cursor xcursor;
|
Cursor xcursor;
|
||||||
MetaCursorReference *cursor_ref;
|
MetaCursorSprite *cursor_sprite;
|
||||||
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (screen);
|
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (screen);
|
||||||
|
|
||||||
cursor_ref = meta_cursor_reference_from_theme (cursor);
|
cursor_sprite = meta_cursor_sprite_from_theme (cursor);
|
||||||
if (cursor_ref == NULL)
|
|
||||||
meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
|
|
||||||
|
|
||||||
meta_cursor_tracker_set_root_cursor (tracker, cursor_ref);
|
if (meta_is_wayland_compositor ())
|
||||||
meta_cursor_reference_unref (cursor_ref);
|
manage_root_cursor_sprite_scale (screen, cursor_sprite);
|
||||||
|
|
||||||
|
meta_cursor_tracker_set_root_cursor (tracker, cursor_sprite);
|
||||||
|
g_object_unref (cursor_sprite);
|
||||||
|
|
||||||
/* Set a cursor for X11 applications that don't specify their own */
|
/* Set a cursor for X11 applications that don't specify their own */
|
||||||
xcursor = meta_display_create_x_cursor (display, cursor);
|
xcursor = meta_display_create_x_cursor (display, cursor);
|
||||||
@@ -1457,6 +1484,25 @@ meta_screen_get_monitor_index_for_rect (MetaScreen *screen,
|
|||||||
return monitor->number;
|
return monitor->number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MetaMonitorInfo *
|
||||||
|
meta_screen_get_monitor_for_point (MetaScreen *screen,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (screen->n_monitor_infos == 1)
|
||||||
|
return &screen->monitor_infos[0];
|
||||||
|
|
||||||
|
for (i = 0; i < screen->n_monitor_infos; i++)
|
||||||
|
{
|
||||||
|
if (POINT_IN_RECT (x, y, screen->monitor_infos[i].rect))
|
||||||
|
return &screen->monitor_infos[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const MetaMonitorInfo*
|
const MetaMonitorInfo*
|
||||||
meta_screen_get_monitor_neighbor (MetaScreen *screen,
|
meta_screen_get_monitor_neighbor (MetaScreen *screen,
|
||||||
int which_monitor,
|
int which_monitor,
|
||||||
|
@@ -176,9 +176,6 @@ struct _MetaWindow
|
|||||||
/* Whether the window is marked as urgent */
|
/* Whether the window is marked as urgent */
|
||||||
guint urgent : 1;
|
guint urgent : 1;
|
||||||
|
|
||||||
/* Whether we have to fullscreen after placement */
|
|
||||||
guint fullscreen_after_placement : 1;
|
|
||||||
|
|
||||||
/* Area to cover when in fullscreen mode. If _NET_WM_FULLSCREEN_MONITORS has
|
/* Area to cover when in fullscreen mode. If _NET_WM_FULLSCREEN_MONITORS has
|
||||||
* been overridden (via a client message), the window will cover the union of
|
* been overridden (via a client message), the window will cover the union of
|
||||||
* these monitors. If not, this is the single monitor which the window's
|
* these monitors. If not, this is the single monitor which the window's
|
||||||
|
@@ -880,7 +880,6 @@ _meta_window_shared_new (MetaDisplay *display,
|
|||||||
window->maximize_vertically_after_placement = FALSE;
|
window->maximize_vertically_after_placement = FALSE;
|
||||||
window->minimize_after_placement = FALSE;
|
window->minimize_after_placement = FALSE;
|
||||||
window->fullscreen = FALSE;
|
window->fullscreen = FALSE;
|
||||||
window->fullscreen_after_placement = FALSE;
|
|
||||||
window->fullscreen_monitors[0] = -1;
|
window->fullscreen_monitors[0] = -1;
|
||||||
window->require_fully_onscreen = TRUE;
|
window->require_fully_onscreen = TRUE;
|
||||||
window->require_on_single_monitor = TRUE;
|
window->require_on_single_monitor = TRUE;
|
||||||
|
@@ -537,11 +537,14 @@ data_device_start_drag (struct wl_client *client,
|
|||||||
drag_source = wl_resource_get_user_data (source_resource);
|
drag_source = wl_resource_get_user_data (source_resource);
|
||||||
|
|
||||||
if (icon_resource &&
|
if (icon_resource &&
|
||||||
meta_wayland_surface_set_role (icon_surface,
|
!meta_wayland_surface_assign_role (icon_surface,
|
||||||
META_WAYLAND_SURFACE_ROLE_DND,
|
META_TYPE_WAYLAND_SURFACE_ROLE_DND))
|
||||||
resource,
|
{
|
||||||
WL_DATA_DEVICE_ERROR_ROLE) != 0)
|
wl_resource_post_error (resource, WL_DATA_DEVICE_ERROR_ROLE,
|
||||||
return;
|
"wl_surface@%d already has a different role",
|
||||||
|
wl_resource_get_id (icon_resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
|
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
|
||||||
meta_wayland_data_device_start_drag (data_device, client,
|
meta_wayland_data_device_start_drag (data_device, client,
|
||||||
|
@@ -477,6 +477,34 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
|||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_keyboard_update_key_state (MetaWaylandKeyboard *keyboard,
|
||||||
|
char *key_vector,
|
||||||
|
int key_vector_len,
|
||||||
|
int offset)
|
||||||
|
{
|
||||||
|
gboolean mods_changed = FALSE;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = offset; i < key_vector_len * 8; i++)
|
||||||
|
{
|
||||||
|
gboolean set = (key_vector[i/8] & (1 << (i % 8))) != 0;
|
||||||
|
|
||||||
|
/* The 'offset' parameter allows the caller to have the indices
|
||||||
|
* into key_vector to either be X-style (base 8) or evdev (base 0), or
|
||||||
|
* something else (unlikely). We subtract 'offset' to convert to evdev
|
||||||
|
* style, then add 8 to convert the "evdev" style keycode back to
|
||||||
|
* the X-style that xkbcommon expects.
|
||||||
|
*/
|
||||||
|
mods_changed |= xkb_state_update_key (keyboard->xkb_info.state,
|
||||||
|
i - offset + 8,
|
||||||
|
set ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mods_changed)
|
||||||
|
notify_modifiers (keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
move_resources (struct wl_list *destination, struct wl_list *source)
|
move_resources (struct wl_list *destination, struct wl_list *source)
|
||||||
{
|
{
|
||||||
|
@@ -85,6 +85,10 @@ void meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard,
|
|||||||
|
|
||||||
gboolean meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
gboolean meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||||
const ClutterKeyEvent *event);
|
const ClutterKeyEvent *event);
|
||||||
|
void meta_wayland_keyboard_update_key_state (MetaWaylandKeyboard *compositor,
|
||||||
|
char *key_vector,
|
||||||
|
int key_vector_len,
|
||||||
|
int offset);
|
||||||
|
|
||||||
void meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
void meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
||||||
MetaWaylandSurface *surface);
|
MetaWaylandSurface *surface);
|
||||||
|
160
src/wayland/meta-wayland-pointer-gesture-pinch.c
Normal file
160
src/wayland/meta-wayland-pointer-gesture-pinch.c
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Wayland Support
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "meta-wayland-pointer-gesture-pinch.h"
|
||||||
|
#include "meta-wayland-pointer.h"
|
||||||
|
#include "meta-wayland-surface.h"
|
||||||
|
#include "pointer-gestures-server-protocol.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_pinch_begin (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
uint32_t serial;
|
||||||
|
|
||||||
|
pointer_client = pointer->focus_client;
|
||||||
|
serial = wl_display_next_serial (pointer->display);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_pinch_update (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
gdouble dx, dy, scale, rotation;
|
||||||
|
|
||||||
|
pointer_client = pointer->focus_client;
|
||||||
|
clutter_event_get_gesture_motion_delta (event, &dx, &dy);
|
||||||
|
rotation = clutter_event_get_gesture_pinch_angle_delta (event);
|
||||||
|
scale = clutter_event_get_gesture_pinch_scale (event);
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_pinch_end (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
gboolean cancelled = FALSE;
|
||||||
|
uint32_t serial;
|
||||||
|
|
||||||
|
pointer_client = pointer->focus_client;
|
||||||
|
serial = wl_display_next_serial (pointer->display);
|
||||||
|
|
||||||
|
if (event->touchpad_pinch.phase == CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL)
|
||||||
|
cancelled = TRUE;
|
||||||
|
|
||||||
|
wl_resource_for_each (resource, &pointer_client->pinch_gesture_resources)
|
||||||
|
{
|
||||||
|
_wl_pointer_gesture_pinch_send_end (resource, serial,
|
||||||
|
clutter_event_get_time (event),
|
||||||
|
cancelled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_pointer_gesture_pinch_handle_event (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type != CLUTTER_TOUCHPAD_PINCH)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!pointer->focus_client)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (event->touchpad_pinch.phase)
|
||||||
|
{
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN:
|
||||||
|
handle_pinch_begin (pointer, event);
|
||||||
|
break;
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE:
|
||||||
|
handle_pinch_update (pointer, event);
|
||||||
|
break;
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_END:
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL:
|
||||||
|
handle_pinch_end (pointer, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_gesture_pinch_destroy (struct wl_client *client,
|
||||||
|
struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
wl_resource_destroy (resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct _wl_pointer_gesture_pinch_interface pointer_gesture_pinch_interface = {
|
||||||
|
pointer_gesture_pinch_destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_pointer_gesture_pinch_create_new_resource (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client,
|
||||||
|
struct wl_resource *gestures_resource,
|
||||||
|
uint32_t id)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *res;
|
||||||
|
|
||||||
|
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,
|
||||||
|
wl_resource_get_version (gestures_resource), id);
|
||||||
|
wl_resource_set_implementation (res, &pointer_gesture_pinch_interface, pointer,
|
||||||
|
meta_wayland_pointer_unbind_pointer_client_resource);
|
||||||
|
wl_list_insert (&pointer_client->pinch_gesture_resources,
|
||||||
|
wl_resource_get_link (res));
|
||||||
|
}
|
39
src/wayland/meta-wayland-pointer-gesture-pinch.h
Normal file
39
src/wayland/meta-wayland-pointer-gesture-pinch.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Wayland Support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Red Hat
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef META_WAYLAND_POINTER_GESTURE_PINCH_H
|
||||||
|
#define META_WAYLAND_POINTER_GESTURE_PINCH_H
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "meta-wayland-types.h"
|
||||||
|
|
||||||
|
gboolean meta_wayland_pointer_gesture_pinch_handle_event (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event);
|
||||||
|
|
||||||
|
void meta_wayland_pointer_gesture_pinch_create_new_resource (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client,
|
||||||
|
struct wl_resource *gestures_resource,
|
||||||
|
uint32_t id);
|
||||||
|
|
||||||
|
#endif /* META_WAYLAND_POINTER_GESTURE_PINCH_H */
|
156
src/wayland/meta-wayland-pointer-gesture-swipe.c
Normal file
156
src/wayland/meta-wayland-pointer-gesture-swipe.c
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Wayland Support
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "meta-wayland-pointer-gesture-swipe.h"
|
||||||
|
#include "meta-wayland-pointer.h"
|
||||||
|
#include "meta-wayland-surface.h"
|
||||||
|
#include "pointer-gestures-server-protocol.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_swipe_begin (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
uint32_t serial, fingers;
|
||||||
|
|
||||||
|
pointer_client = pointer->focus_client;
|
||||||
|
serial = wl_display_next_serial (pointer->display);
|
||||||
|
fingers = clutter_event_get_gesture_swipe_finger_count (event);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_swipe_update (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
gdouble dx, dy;
|
||||||
|
|
||||||
|
pointer_client = pointer->focus_client;
|
||||||
|
clutter_event_get_gesture_motion_delta (event, &dx, &dy);
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_swipe_end (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *resource;
|
||||||
|
gboolean cancelled = FALSE;
|
||||||
|
uint32_t serial;
|
||||||
|
|
||||||
|
pointer_client = pointer->focus_client;
|
||||||
|
serial = wl_display_next_serial (pointer->display);
|
||||||
|
|
||||||
|
if (event->touchpad_swipe.phase == CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL)
|
||||||
|
cancelled = TRUE;
|
||||||
|
|
||||||
|
wl_resource_for_each (resource, &pointer_client->swipe_gesture_resources)
|
||||||
|
{
|
||||||
|
_wl_pointer_gesture_swipe_send_end (resource, serial,
|
||||||
|
clutter_event_get_time (event),
|
||||||
|
cancelled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_pointer_gesture_swipe_handle_event (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type != CLUTTER_TOUCHPAD_SWIPE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!pointer->focus_client)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (event->touchpad_swipe.phase)
|
||||||
|
{
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN:
|
||||||
|
handle_swipe_begin (pointer, event);
|
||||||
|
break;
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE:
|
||||||
|
handle_swipe_update (pointer, event);
|
||||||
|
break;
|
||||||
|
case CLUTTER_TOUCHPAD_GESTURE_PHASE_END:
|
||||||
|
handle_swipe_end (pointer, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_gesture_swipe_release (struct wl_client *client,
|
||||||
|
struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
wl_resource_destroy (resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct _wl_pointer_gesture_swipe_interface pointer_gesture_swipe_interface = {
|
||||||
|
pointer_gesture_swipe_release
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_pointer_gesture_swipe_create_new_resource (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client,
|
||||||
|
struct wl_resource *pointer_resource,
|
||||||
|
uint32_t id)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_resource *res;
|
||||||
|
|
||||||
|
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,
|
||||||
|
wl_resource_get_version (pointer_resource), id);
|
||||||
|
wl_resource_set_implementation (res, &pointer_gesture_swipe_interface, pointer,
|
||||||
|
meta_wayland_pointer_unbind_pointer_client_resource);
|
||||||
|
wl_list_insert (&pointer_client->swipe_gesture_resources,
|
||||||
|
wl_resource_get_link (res));
|
||||||
|
}
|
39
src/wayland/meta-wayland-pointer-gesture-swipe.h
Normal file
39
src/wayland/meta-wayland-pointer-gesture-swipe.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Wayland Support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Red Hat
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef META_WAYLAND_POINTER_GESTURE_SWIPE_H
|
||||||
|
#define META_WAYLAND_POINTER_GESTURE_SWIPE_H
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "meta-wayland-types.h"
|
||||||
|
|
||||||
|
gboolean meta_wayland_pointer_gesture_swipe_handle_event (MetaWaylandPointer *pointer,
|
||||||
|
const ClutterEvent *event);
|
||||||
|
|
||||||
|
void meta_wayland_pointer_gesture_swipe_create_new_resource (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client,
|
||||||
|
struct wl_resource *pointer_resource,
|
||||||
|
uint32_t id);
|
||||||
|
|
||||||
|
#endif /* META_WAYLAND_POINTER_GESTURE_SWIPE_H */
|
90
src/wayland/meta-wayland-pointer-gestures.c
Normal file
90
src/wayland/meta-wayland-pointer-gestures.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Wayland Support
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include "meta-wayland-pointer-gestures.h"
|
||||||
|
#include "pointer-gestures-server-protocol.h"
|
||||||
|
#include "meta-wayland-versions.h"
|
||||||
|
#include "meta-wayland-private.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
gestures_get_swipe (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);
|
||||||
|
|
||||||
|
meta_wayland_pointer_gesture_swipe_create_new_resource (pointer, client, resource, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gestures_get_pinch (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);
|
||||||
|
|
||||||
|
meta_wayland_pointer_gesture_pinch_create_new_resource (pointer, client, resource, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct _wl_pointer_gestures_interface pointer_gestures_interface = {
|
||||||
|
gestures_get_swipe,
|
||||||
|
gestures_get_pinch
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
bind_pointer_gestures (struct wl_client *client,
|
||||||
|
void *data,
|
||||||
|
guint32 version,
|
||||||
|
guint32 id)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_resource_set_implementation (resource, &pointer_gestures_interface,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_pointer_gestures_init (MetaWaylandCompositor *compositor)
|
||||||
|
{
|
||||||
|
wl_global_create (compositor->wayland_display,
|
||||||
|
&_wl_pointer_gestures_interface,
|
||||||
|
META__WL_POINTER_GESTURES_VERSION,
|
||||||
|
NULL, bind_pointer_gestures);
|
||||||
|
}
|
32
src/wayland/meta-wayland-pointer-gestures.h
Normal file
32
src/wayland/meta-wayland-pointer-gestures.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Wayland Support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Red Hat
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef META_WAYLAND_POINTER_GESTURES_H
|
||||||
|
#define META_WAYLAND_POINTER_GESTURES_H
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "meta-wayland-types.h"
|
||||||
|
|
||||||
|
void meta_wayland_pointer_gestures_init (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
|
#endif /* META_WAYLAND_POINTER_GESTURES_H */
|
@@ -44,24 +44,161 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <clutter/clutter.h>
|
#include <clutter/clutter.h>
|
||||||
|
#include <cogl/cogl.h>
|
||||||
|
#include <cogl/cogl-wayland-server.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
#include "meta-wayland-pointer.h"
|
#include "meta-wayland-pointer.h"
|
||||||
#include "meta-wayland-popup.h"
|
#include "meta-wayland-popup.h"
|
||||||
#include "meta-wayland-private.h"
|
#include "meta-wayland-private.h"
|
||||||
|
#include "meta-wayland-surface.h"
|
||||||
#include "meta-wayland-buffer.h"
|
#include "meta-wayland-buffer.h"
|
||||||
#include "meta-cursor.h"
|
#include "meta-cursor.h"
|
||||||
#include "meta-cursor-tracker-private.h"
|
#include "meta-cursor-tracker-private.h"
|
||||||
#include "meta-surface-actor-wayland.h"
|
#include "meta-surface-actor-wayland.h"
|
||||||
|
#include "meta/meta-cursor-tracker.h"
|
||||||
|
#include "backends/meta-backend-private.h"
|
||||||
|
#include "backends/meta-cursor-tracker-private.h"
|
||||||
|
#include "backends/meta-cursor-renderer.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
|
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
|
||||||
|
|
||||||
static void
|
struct _MetaWaylandSurfaceRoleCursor
|
||||||
unbind_resource (struct wl_resource *resource)
|
|
||||||
{
|
{
|
||||||
|
MetaWaylandSurfaceRole parent;
|
||||||
|
|
||||||
|
int hot_x;
|
||||||
|
int hot_y;
|
||||||
|
MetaCursorSprite *cursor_sprite;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_cursor_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleCursor,
|
||||||
|
meta_wayland_surface_role_cursor,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer);
|
||||||
|
|
||||||
|
static MetaWaylandPointerClient *
|
||||||
|
meta_wayland_pointer_client_new (void)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
|
||||||
|
pointer_client = g_slice_new0 (MetaWaylandPointerClient);
|
||||||
|
wl_list_init (&pointer_client->pointer_resources);
|
||||||
|
wl_list_init (&pointer_client->swipe_gesture_resources);
|
||||||
|
wl_list_init (&pointer_client->pinch_gesture_resources);
|
||||||
|
|
||||||
|
return pointer_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
|
||||||
|
{
|
||||||
|
struct wl_resource *resource, *next;
|
||||||
|
|
||||||
|
/* Since we make every wl_pointer resource defunct when we stop advertising
|
||||||
|
* the pointer capability on the wl_seat, we need to make sure all the
|
||||||
|
* resources in the pointer client instance gets removed.
|
||||||
|
*/
|
||||||
|
wl_resource_for_each_safe (resource, next, &pointer_client->pointer_resources)
|
||||||
|
{
|
||||||
|
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->swipe_gesture_resources)
|
||||||
|
{
|
||||||
|
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->pinch_gesture_resources)
|
||||||
|
{
|
||||||
|
wl_list_remove (wl_resource_get_link (resource));
|
||||||
|
wl_list_init (wl_resource_get_link (resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slice_free (MetaWaylandPointerClient, pointer_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandPointerClient *
|
||||||
|
meta_wayland_pointer_get_pointer_client (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client)
|
||||||
|
{
|
||||||
|
if (!pointer->pointer_clients)
|
||||||
|
return NULL;
|
||||||
|
return g_hash_table_lookup (pointer->pointer_clients, client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaWaylandPointerClient *
|
||||||
|
meta_wayland_pointer_ensure_pointer_client (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
|
||||||
|
pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
|
||||||
|
if (pointer_client)
|
||||||
|
return pointer_client;
|
||||||
|
|
||||||
|
pointer_client = meta_wayland_pointer_client_new ();
|
||||||
|
g_hash_table_insert (pointer->pointer_clients, client, pointer_client);
|
||||||
|
|
||||||
|
if (!pointer->focus_client &&
|
||||||
|
pointer->focus_surface &&
|
||||||
|
wl_resource_get_client (pointer->focus_surface->resource) == client)
|
||||||
|
pointer->focus_client = pointer_client;
|
||||||
|
|
||||||
|
return pointer_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_pointer_cleanup_pointer_client (MetaWaylandPointer *pointer,
|
||||||
|
MetaWaylandPointerClient *pointer_client,
|
||||||
|
struct wl_client *client)
|
||||||
|
{
|
||||||
|
if (meta_wayland_pointer_client_is_empty (pointer_client))
|
||||||
|
{
|
||||||
|
if (pointer->focus_client == pointer_client)
|
||||||
|
pointer->focus_client = NULL;
|
||||||
|
g_hash_table_remove (pointer->pointer_clients, client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
MetaWaylandPointer *pointer = wl_resource_get_user_data (resource);
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
struct wl_client *client = wl_resource_get_client (resource);
|
||||||
|
|
||||||
wl_list_remove (wl_resource_get_link (resource));
|
wl_list_remove (wl_resource_get_link (resource));
|
||||||
|
|
||||||
|
pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
|
||||||
|
if (!pointer_client)
|
||||||
|
{
|
||||||
|
/* This happens if all pointer devices were unplugged and no new resources
|
||||||
|
* were created by the client.
|
||||||
|
*
|
||||||
|
* If this is a resource that was previously made defunct, pointer_client
|
||||||
|
* be non-NULL but it is harmless since the below cleanup call will be
|
||||||
|
* prevented from removing the pointer client because of valid resources.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_wayland_pointer_cleanup_pointer_client (pointer,
|
||||||
|
pointer_client,
|
||||||
|
client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -92,32 +229,6 @@ sync_focus_surface (MetaWaylandPointer *pointer)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
set_cursor_surface (MetaWaylandPointer *pointer,
|
|
||||||
MetaWaylandSurface *surface)
|
|
||||||
{
|
|
||||||
if (pointer->cursor_surface == surface)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pointer->cursor_surface)
|
|
||||||
wl_list_remove (&pointer->cursor_surface_destroy_listener.link);
|
|
||||||
|
|
||||||
pointer->cursor_surface = surface;
|
|
||||||
|
|
||||||
if (pointer->cursor_surface)
|
|
||||||
wl_resource_add_destroy_listener (pointer->cursor_surface->resource,
|
|
||||||
&pointer->cursor_surface_destroy_listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pointer_handle_cursor_surface_destroy (struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, cursor_surface_destroy_listener);
|
|
||||||
|
|
||||||
set_cursor_surface (pointer, NULL);
|
|
||||||
meta_wayland_pointer_update_cursor_surface (pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
|
pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
@@ -131,17 +242,20 @@ meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
|
|||||||
const ClutterEvent *event)
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wl_list *l;
|
uint32_t time;
|
||||||
|
wl_fixed_t sx, sy;
|
||||||
|
|
||||||
l = &pointer->focus_resource_list;
|
if (!pointer->focus_client)
|
||||||
wl_resource_for_each(resource, l)
|
return;
|
||||||
|
|
||||||
|
time = clutter_event_get_time (event);
|
||||||
|
meta_wayland_pointer_get_relative_coordinates (pointer,
|
||||||
|
pointer->focus_surface,
|
||||||
|
&sx, &sy);
|
||||||
|
|
||||||
|
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
|
||||||
{
|
{
|
||||||
wl_fixed_t sx, sy;
|
wl_pointer_send_motion (resource, time, sx, sy);
|
||||||
|
|
||||||
meta_wayland_pointer_get_relative_coordinates (pointer,
|
|
||||||
pointer->focus_surface,
|
|
||||||
&sx, &sy);
|
|
||||||
wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,19 +264,21 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
|
|||||||
const ClutterEvent *event)
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wl_list *l;
|
|
||||||
ClutterEventType event_type;
|
ClutterEventType event_type;
|
||||||
|
|
||||||
event_type = clutter_event_type (event);
|
event_type = clutter_event_type (event);
|
||||||
|
|
||||||
l = &pointer->focus_resource_list;
|
if (pointer->focus_client &&
|
||||||
if (!wl_list_empty (l))
|
!wl_list_empty (&pointer->focus_client->pointer_resources))
|
||||||
{
|
{
|
||||||
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
|
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
|
||||||
struct wl_display *display = wl_client_get_display (client);
|
struct wl_display *display = wl_client_get_display (client);
|
||||||
|
uint32_t time;
|
||||||
uint32_t button;
|
uint32_t button;
|
||||||
uint32_t serial;
|
uint32_t serial;
|
||||||
|
|
||||||
|
time = clutter_event_get_time (event);
|
||||||
|
|
||||||
button = clutter_event_get_button (event);
|
button = clutter_event_get_button (event);
|
||||||
switch (button)
|
switch (button)
|
||||||
{
|
{
|
||||||
@@ -183,10 +299,10 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
|
|||||||
|
|
||||||
serial = wl_display_next_serial (display);
|
serial = wl_display_next_serial (display);
|
||||||
|
|
||||||
wl_resource_for_each(resource, l)
|
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
|
||||||
{
|
{
|
||||||
wl_pointer_send_button (resource, serial,
|
wl_pointer_send_button (resource, serial,
|
||||||
clutter_event_get_time (event), button,
|
time, button,
|
||||||
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
|
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,23 +347,32 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
|
|||||||
default_grab_button
|
default_grab_button
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_pointer_on_cursor_changed (MetaCursorTracker *cursor_tracker,
|
||||||
|
MetaWaylandPointer *pointer)
|
||||||
|
{
|
||||||
|
if (pointer->cursor_surface)
|
||||||
|
meta_wayland_surface_update_outputs (pointer->cursor_surface);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
|
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
|
||||||
struct wl_display *display)
|
struct wl_display *display)
|
||||||
{
|
{
|
||||||
|
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||||
ClutterDeviceManager *manager;
|
ClutterDeviceManager *manager;
|
||||||
|
|
||||||
memset (pointer, 0, sizeof *pointer);
|
memset (pointer, 0, sizeof *pointer);
|
||||||
|
|
||||||
pointer->display = display;
|
pointer->display = display;
|
||||||
|
|
||||||
wl_list_init (&pointer->resource_list);
|
pointer->pointer_clients =
|
||||||
wl_list_init (&pointer->focus_resource_list);
|
g_hash_table_new_full (NULL, NULL, NULL,
|
||||||
|
(GDestroyNotify) meta_wayland_pointer_client_free);
|
||||||
|
|
||||||
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
|
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
|
||||||
|
|
||||||
pointer->cursor_surface = NULL;
|
pointer->cursor_surface = NULL;
|
||||||
pointer->cursor_surface_destroy_listener.notify = pointer_handle_cursor_surface_destroy;
|
|
||||||
|
|
||||||
pointer->default_grab.interface = &default_pointer_grab_interface;
|
pointer->default_grab.interface = &default_pointer_grab_interface;
|
||||||
pointer->default_grab.pointer = pointer;
|
pointer->default_grab.pointer = pointer;
|
||||||
@@ -256,16 +381,26 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
|
|||||||
manager = clutter_device_manager_get_default ();
|
manager = clutter_device_manager_get_default ();
|
||||||
pointer->device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
|
pointer->device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
|
||||||
|
|
||||||
pointer->cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
g_signal_connect (cursor_tracker,
|
||||||
|
"cursor-changed",
|
||||||
|
G_CALLBACK (meta_wayland_pointer_on_cursor_changed),
|
||||||
|
pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
|
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
|
||||||
{
|
{
|
||||||
meta_wayland_pointer_set_focus (pointer, NULL);
|
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||||
set_cursor_surface (pointer, NULL);
|
|
||||||
|
|
||||||
|
g_signal_handlers_disconnect_by_func (cursor_tracker,
|
||||||
|
(gpointer) meta_wayland_pointer_on_cursor_changed,
|
||||||
|
pointer);
|
||||||
|
|
||||||
|
meta_wayland_pointer_set_focus (pointer, NULL);
|
||||||
|
|
||||||
|
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
|
||||||
pointer->display = NULL;
|
pointer->display = NULL;
|
||||||
|
pointer->cursor_surface = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -358,7 +493,6 @@ handle_scroll_event (MetaWaylandPointer *pointer,
|
|||||||
const ClutterEvent *event)
|
const ClutterEvent *event)
|
||||||
{
|
{
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wl_list *l;
|
|
||||||
wl_fixed_t x_value = 0, y_value = 0;
|
wl_fixed_t x_value = 0, y_value = 0;
|
||||||
|
|
||||||
if (clutter_event_is_pointer_emulated (event))
|
if (clutter_event_is_pointer_emulated (event))
|
||||||
@@ -399,15 +533,17 @@ handle_scroll_event (MetaWaylandPointer *pointer,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
l = &pointer->focus_resource_list;
|
if (pointer->focus_client)
|
||||||
wl_resource_for_each (resource, l)
|
|
||||||
{
|
{
|
||||||
if (x_value)
|
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
|
||||||
wl_pointer_send_axis (resource, clutter_event_get_time (event),
|
{
|
||||||
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
|
if (x_value)
|
||||||
if (y_value)
|
wl_pointer_send_axis (resource, clutter_event_get_time (event),
|
||||||
wl_pointer_send_axis (resource, clutter_event_get_time (event),
|
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
|
||||||
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
|
if (y_value)
|
||||||
|
wl_pointer_send_axis (resource, clutter_event_get_time (event),
|
||||||
|
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,6 +566,14 @@ meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
|
|||||||
handle_scroll_event (pointer, event);
|
handle_scroll_event (pointer, event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CLUTTER_TOUCHPAD_SWIPE:
|
||||||
|
meta_wayland_pointer_gesture_swipe_handle_event (pointer, event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLUTTER_TOUCHPAD_PINCH:
|
||||||
|
meta_wayland_pointer_gesture_pinch_handle_event (pointer, event);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -437,29 +581,6 @@ meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
move_resources (struct wl_list *destination, struct wl_list *source)
|
|
||||||
{
|
|
||||||
wl_list_insert_list (destination, source);
|
|
||||||
wl_list_init (source);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
move_resources_for_client (struct wl_list *destination,
|
|
||||||
struct wl_list *source,
|
|
||||||
struct wl_client *client)
|
|
||||||
{
|
|
||||||
struct wl_resource *resource, *tmp;
|
|
||||||
wl_resource_for_each_safe (resource, tmp, source)
|
|
||||||
{
|
|
||||||
if (wl_resource_get_client (resource) == client)
|
|
||||||
{
|
|
||||||
wl_list_remove (wl_resource_get_link (resource));
|
|
||||||
wl_list_insert (destination, wl_resource_get_link (resource));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
broadcast_focus (MetaWaylandPointer *pointer,
|
broadcast_focus (MetaWaylandPointer *pointer,
|
||||||
struct wl_resource *resource)
|
struct wl_resource *resource)
|
||||||
@@ -482,22 +603,23 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
|||||||
|
|
||||||
if (pointer->focus_surface != NULL)
|
if (pointer->focus_surface != NULL)
|
||||||
{
|
{
|
||||||
|
struct wl_client *client =
|
||||||
|
wl_resource_get_client (pointer->focus_surface->resource);
|
||||||
|
struct wl_display *display = wl_client_get_display (client);
|
||||||
|
uint32_t serial;
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wl_list *l;
|
|
||||||
|
|
||||||
l = &pointer->focus_resource_list;
|
serial = wl_display_next_serial (display);
|
||||||
if (!wl_list_empty (l))
|
|
||||||
|
if (pointer->focus_client)
|
||||||
{
|
{
|
||||||
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
|
wl_resource_for_each (resource,
|
||||||
struct wl_display *display = wl_client_get_display (client);
|
&pointer->focus_client->pointer_resources)
|
||||||
uint32_t serial = wl_display_next_serial (display);
|
|
||||||
|
|
||||||
wl_resource_for_each (resource, l)
|
|
||||||
{
|
{
|
||||||
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
|
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
move_resources (&pointer->resource_list, &pointer->focus_resource_list);
|
pointer->focus_client = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_remove (&pointer->focus_surface_listener.link);
|
wl_list_remove (&pointer->focus_surface_listener.link);
|
||||||
@@ -506,8 +628,9 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
|||||||
|
|
||||||
if (surface != NULL)
|
if (surface != NULL)
|
||||||
{
|
{
|
||||||
|
struct wl_client *client = wl_resource_get_client (surface->resource);
|
||||||
|
struct wl_display *display = wl_client_get_display (client);
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wl_list *l;
|
|
||||||
ClutterPoint pos;
|
ClutterPoint pos;
|
||||||
|
|
||||||
pointer->focus_surface = surface;
|
pointer->focus_surface = surface;
|
||||||
@@ -521,18 +644,14 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
|||||||
clutter_get_current_event_time (),
|
clutter_get_current_event_time (),
|
||||||
pos.x, pos.y);
|
pos.x, pos.y);
|
||||||
|
|
||||||
move_resources_for_client (&pointer->focus_resource_list,
|
pointer->focus_client =
|
||||||
&pointer->resource_list,
|
meta_wayland_pointer_get_pointer_client (pointer, client);
|
||||||
wl_resource_get_client (pointer->focus_surface->resource));
|
if (pointer->focus_client)
|
||||||
|
|
||||||
l = &pointer->focus_resource_list;
|
|
||||||
if (!wl_list_empty (l))
|
|
||||||
{
|
{
|
||||||
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
|
|
||||||
struct wl_display *display = wl_client_get_display (client);
|
|
||||||
pointer->focus_serial = wl_display_next_serial (display);
|
pointer->focus_serial = wl_display_next_serial (display);
|
||||||
|
|
||||||
wl_resource_for_each (resource, l)
|
wl_resource_for_each (resource,
|
||||||
|
&pointer->focus_client->pointer_resources)
|
||||||
{
|
{
|
||||||
broadcast_focus (pointer, resource);
|
broadcast_focus (pointer, resource);
|
||||||
}
|
}
|
||||||
@@ -623,34 +742,104 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
|
|||||||
*sy = wl_fixed_from_double (yf) / surface->scale;
|
*sy = wl_fixed_from_double (yf) / surface->scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
|
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
|
||||||
{
|
{
|
||||||
if (pointer->cursor_tracker == NULL)
|
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||||
return;
|
|
||||||
|
|
||||||
if (pointer->current)
|
if (pointer->current)
|
||||||
{
|
{
|
||||||
MetaCursorReference *cursor;
|
MetaCursorSprite *cursor_sprite = NULL;
|
||||||
|
|
||||||
if (pointer->cursor_surface && pointer->cursor_surface->buffer)
|
if (pointer->cursor_surface)
|
||||||
{
|
{
|
||||||
struct wl_resource *buffer = pointer->cursor_surface->buffer->resource;
|
MetaWaylandSurfaceRoleCursor *cursor_role =
|
||||||
cursor = meta_cursor_reference_from_buffer (buffer,
|
META_WAYLAND_SURFACE_ROLE_CURSOR (pointer->cursor_surface->role);
|
||||||
pointer->hotspot_x,
|
|
||||||
pointer->hotspot_y);
|
cursor_sprite = cursor_role->cursor_sprite;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
cursor = NULL;
|
|
||||||
|
|
||||||
meta_cursor_tracker_set_window_cursor (pointer->cursor_tracker, cursor);
|
meta_cursor_tracker_set_window_cursor (cursor_tracker, cursor_sprite);
|
||||||
|
|
||||||
if (cursor)
|
|
||||||
meta_cursor_reference_unref (cursor);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
meta_cursor_tracker_unset_window_cursor (pointer->cursor_tracker);
|
meta_cursor_tracker_unset_window_cursor (cursor_tracker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_cursor_sprite_texture (MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
MetaCursorRenderer *cursor_renderer =
|
||||||
|
meta_backend_get_cursor_renderer (meta_get_backend ());
|
||||||
|
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||||
|
MetaWaylandSurfaceRoleCursor *cursor_role =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
|
||||||
|
MetaCursorSprite *cursor_sprite = cursor_role->cursor_sprite;
|
||||||
|
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||||
|
CoglContext *cogl_context =
|
||||||
|
clutter_backend_get_cogl_context (clutter_backend);
|
||||||
|
CoglTexture *texture;
|
||||||
|
|
||||||
|
if (surface->buffer)
|
||||||
|
{
|
||||||
|
struct wl_resource *buffer;
|
||||||
|
|
||||||
|
buffer = surface->buffer->resource;
|
||||||
|
texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context,
|
||||||
|
buffer,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
meta_cursor_sprite_set_texture (cursor_sprite,
|
||||||
|
texture,
|
||||||
|
cursor_role->hot_x * surface->scale,
|
||||||
|
cursor_role->hot_y * surface->scale);
|
||||||
|
meta_cursor_renderer_realize_cursor_from_wl_buffer (cursor_renderer,
|
||||||
|
cursor_sprite,
|
||||||
|
buffer);
|
||||||
|
cogl_object_unref (texture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta_cursor_sprite_set_texture (cursor_sprite, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_sprite == meta_cursor_tracker_get_displayed_cursor (cursor_tracker))
|
||||||
|
meta_cursor_renderer_force_update (cursor_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
MetaWaylandSurfaceRoleCursor *cursor_role)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_role);
|
||||||
|
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
|
||||||
|
MetaDisplay *display = meta_get_display ();
|
||||||
|
MetaScreen *screen = display->screen;
|
||||||
|
const MetaMonitorInfo *monitor;
|
||||||
|
|
||||||
|
monitor = meta_screen_get_monitor_for_point (screen, x, y);
|
||||||
|
meta_cursor_sprite_set_texture_scale (cursor_sprite,
|
||||||
|
(float)monitor->scale / surface->scale);
|
||||||
|
meta_wayland_surface_update_outputs (surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_pointer_set_cursor_surface (MetaWaylandPointer *pointer,
|
||||||
|
MetaWaylandSurface *cursor_surface)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *prev_cursor_surface;
|
||||||
|
|
||||||
|
prev_cursor_surface = pointer->cursor_surface;
|
||||||
|
pointer->cursor_surface = cursor_surface;
|
||||||
|
|
||||||
|
if (prev_cursor_surface != cursor_surface)
|
||||||
|
{
|
||||||
|
if (prev_cursor_surface)
|
||||||
|
meta_wayland_surface_update_outputs (prev_cursor_surface);
|
||||||
|
meta_wayland_pointer_update_cursor_surface (pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,7 +848,7 @@ pointer_set_cursor (struct wl_client *client,
|
|||||||
struct wl_resource *resource,
|
struct wl_resource *resource,
|
||||||
uint32_t serial,
|
uint32_t serial,
|
||||||
struct wl_resource *surface_resource,
|
struct wl_resource *surface_resource,
|
||||||
int32_t x, int32_t y)
|
int32_t hot_x, int32_t hot_y)
|
||||||
{
|
{
|
||||||
MetaWaylandPointer *pointer = wl_resource_get_user_data (resource);
|
MetaWaylandPointer *pointer = wl_resource_get_user_data (resource);
|
||||||
MetaWaylandSurface *surface;
|
MetaWaylandSurface *surface;
|
||||||
@@ -673,19 +862,38 @@ pointer_set_cursor (struct wl_client *client,
|
|||||||
if (pointer->focus_serial - serial > G_MAXUINT32 / 2)
|
if (pointer->focus_serial - serial > G_MAXUINT32 / 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface)
|
if (surface &&
|
||||||
|
!meta_wayland_surface_assign_role (surface,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR))
|
||||||
{
|
{
|
||||||
if (meta_wayland_surface_set_role (surface,
|
wl_resource_post_error (resource, WL_POINTER_ERROR_ROLE,
|
||||||
META_WAYLAND_SURFACE_ROLE_CURSOR,
|
"wl_surface@%d already has a different role",
|
||||||
resource,
|
wl_resource_get_id (surface_resource));
|
||||||
WL_POINTER_ERROR_ROLE) != 0)
|
return;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer->hotspot_x = x;
|
if (surface)
|
||||||
pointer->hotspot_y = y;
|
{
|
||||||
set_cursor_surface (pointer, surface);
|
MetaWaylandSurfaceRoleCursor *cursor_role;
|
||||||
meta_wayland_pointer_update_cursor_surface (pointer);
|
|
||||||
|
cursor_role = META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
|
||||||
|
if (!cursor_role->cursor_sprite)
|
||||||
|
{
|
||||||
|
cursor_role->cursor_sprite = meta_cursor_sprite_new ();
|
||||||
|
g_signal_connect_object (cursor_role->cursor_sprite,
|
||||||
|
"prepare-at",
|
||||||
|
G_CALLBACK (cursor_sprite_prepare_at),
|
||||||
|
cursor_role,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor_role->hot_x = hot_x;
|
||||||
|
cursor_role->hot_y = hot_y;
|
||||||
|
|
||||||
|
update_cursor_sprite_texture (surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_wayland_pointer_set_cursor_surface (pointer, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -707,19 +915,19 @@ meta_wayland_pointer_create_new_resource (MetaWaylandPointer *pointer,
|
|||||||
uint32_t id)
|
uint32_t id)
|
||||||
{
|
{
|
||||||
struct wl_resource *cr;
|
struct wl_resource *cr;
|
||||||
|
MetaWaylandPointerClient *pointer_client;
|
||||||
|
|
||||||
cr = wl_resource_create (client, &wl_pointer_interface, wl_resource_get_version (seat_resource), id);
|
cr = wl_resource_create (client, &wl_pointer_interface, wl_resource_get_version (seat_resource), id);
|
||||||
wl_resource_set_implementation (cr, &pointer_interface, pointer, unbind_resource);
|
wl_resource_set_implementation (cr, &pointer_interface, pointer,
|
||||||
|
meta_wayland_pointer_unbind_pointer_client_resource);
|
||||||
|
|
||||||
if (pointer->focus_surface && wl_resource_get_client (pointer->focus_surface->resource) == client)
|
pointer_client = meta_wayland_pointer_ensure_pointer_client (pointer, client);
|
||||||
{
|
|
||||||
wl_list_insert (&pointer->focus_resource_list, wl_resource_get_link (cr));
|
wl_list_insert (&pointer_client->pointer_resources,
|
||||||
broadcast_focus (pointer, cr);
|
wl_resource_get_link (cr));
|
||||||
}
|
|
||||||
else
|
if (pointer->focus_client == pointer_client)
|
||||||
{
|
broadcast_focus (pointer, cr);
|
||||||
wl_list_insert (&pointer->resource_list, wl_resource_get_link (cr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@@ -749,3 +957,99 @@ meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer)
|
|||||||
grab = (MetaWaylandPopupGrab*)pointer->grab;
|
grab = (MetaWaylandPopupGrab*)pointer->grab;
|
||||||
return meta_wayland_popup_grab_get_top_popup(grab);
|
return meta_wayland_popup_grab_get_top_popup(grab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
|
||||||
|
meta_wayland_surface_queue_pending_frame_callbacks (surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaWaylandPendingState *pending)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
|
||||||
|
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
|
||||||
|
|
||||||
|
if (pending->newly_attached)
|
||||||
|
update_cursor_sprite_texture (surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
cursor_surface_role_is_on_output (MetaWaylandSurfaceRole *role,
|
||||||
|
MetaMonitorInfo *monitor)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (role);
|
||||||
|
MetaWaylandPointer *pointer = &surface->compositor->seat->pointer;
|
||||||
|
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||||
|
MetaCursorRenderer *cursor_renderer =
|
||||||
|
meta_backend_get_cursor_renderer (meta_get_backend ());
|
||||||
|
MetaWaylandSurfaceRoleCursor *cursor_role =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
|
||||||
|
MetaCursorSprite *displayed_cursor_sprite;
|
||||||
|
MetaRectangle rect;
|
||||||
|
|
||||||
|
if (surface != pointer->cursor_surface)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
displayed_cursor_sprite =
|
||||||
|
meta_cursor_tracker_get_displayed_cursor (cursor_tracker);
|
||||||
|
if (!displayed_cursor_sprite)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (cursor_role->cursor_sprite != displayed_cursor_sprite)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
|
||||||
|
cursor_role->cursor_sprite);
|
||||||
|
return meta_rectangle_overlap (&rect, &monitor->rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_surface_role_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleCursor *cursor_role =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CURSOR (object);
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
|
||||||
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||||
|
MetaWaylandPointer *pointer = &compositor->seat->pointer;
|
||||||
|
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||||
|
|
||||||
|
g_signal_handlers_disconnect_by_func (cursor_tracker,
|
||||||
|
(gpointer) cursor_sprite_prepare_at,
|
||||||
|
cursor_role);
|
||||||
|
|
||||||
|
if (pointer->cursor_surface == surface)
|
||||||
|
pointer->cursor_surface = NULL;
|
||||||
|
meta_wayland_pointer_update_cursor_surface (pointer);
|
||||||
|
|
||||||
|
g_clear_object (&cursor_role->cursor_sprite);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (meta_wayland_surface_role_cursor_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_cursor_init (MetaWaylandSurfaceRoleCursor *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_cursor_class_init (MetaWaylandSurfaceRoleCursorClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = cursor_surface_role_assigned;
|
||||||
|
surface_role_class->commit = cursor_surface_role_commit;
|
||||||
|
surface_role_class->is_on_output = cursor_surface_role_is_on_output;
|
||||||
|
|
||||||
|
object_class->dispose = cursor_surface_role_dispose;
|
||||||
|
}
|
||||||
|
@@ -25,9 +25,18 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "meta-wayland-types.h"
|
#include "meta-wayland-types.h"
|
||||||
|
#include "meta-wayland-pointer-gesture-swipe.h"
|
||||||
|
#include "meta-wayland-pointer-gesture-pinch.h"
|
||||||
|
#include "meta-wayland-surface.h"
|
||||||
|
|
||||||
#include <meta/meta-cursor-tracker.h>
|
#include <meta/meta-cursor-tracker.h>
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR (meta_wayland_surface_role_cursor_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleCursor,
|
||||||
|
meta_wayland_surface_role_cursor,
|
||||||
|
META, WAYLAND_SURFACE_ROLE_CURSOR,
|
||||||
|
MetaWaylandSurfaceRole);
|
||||||
|
|
||||||
struct _MetaWaylandPointerGrabInterface
|
struct _MetaWaylandPointerGrabInterface
|
||||||
{
|
{
|
||||||
void (*focus) (MetaWaylandPointerGrab *grab,
|
void (*focus) (MetaWaylandPointerGrab *grab,
|
||||||
@@ -44,22 +53,26 @@ struct _MetaWaylandPointerGrab
|
|||||||
MetaWaylandPointer *pointer;
|
MetaWaylandPointer *pointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _MetaWaylandPointerClient
|
||||||
|
{
|
||||||
|
struct wl_list pointer_resources;
|
||||||
|
struct wl_list swipe_gesture_resources;
|
||||||
|
struct wl_list pinch_gesture_resources;
|
||||||
|
};
|
||||||
|
|
||||||
struct _MetaWaylandPointer
|
struct _MetaWaylandPointer
|
||||||
{
|
{
|
||||||
struct wl_display *display;
|
struct wl_display *display;
|
||||||
|
|
||||||
struct wl_list resource_list;
|
MetaWaylandPointerClient *focus_client;
|
||||||
struct wl_list focus_resource_list;
|
GHashTable *pointer_clients;
|
||||||
|
|
||||||
MetaWaylandSurface *focus_surface;
|
MetaWaylandSurface *focus_surface;
|
||||||
struct wl_listener focus_surface_listener;
|
struct wl_listener focus_surface_listener;
|
||||||
guint32 focus_serial;
|
guint32 focus_serial;
|
||||||
guint32 click_serial;
|
guint32 click_serial;
|
||||||
|
|
||||||
MetaCursorTracker *cursor_tracker;
|
|
||||||
MetaWaylandSurface *cursor_surface;
|
MetaWaylandSurface *cursor_surface;
|
||||||
struct wl_listener cursor_surface_destroy_listener;
|
|
||||||
int hotspot_x, hotspot_y;
|
|
||||||
|
|
||||||
MetaWaylandPointerGrab *grab;
|
MetaWaylandPointerGrab *grab;
|
||||||
MetaWaylandPointerGrab default_grab;
|
MetaWaylandPointerGrab default_grab;
|
||||||
@@ -111,8 +124,6 @@ void meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
|
|||||||
wl_fixed_t *x,
|
wl_fixed_t *x,
|
||||||
wl_fixed_t *y);
|
wl_fixed_t *y);
|
||||||
|
|
||||||
void meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer);
|
|
||||||
|
|
||||||
void meta_wayland_pointer_create_new_resource (MetaWaylandPointer *pointer,
|
void meta_wayland_pointer_create_new_resource (MetaWaylandPointer *pointer,
|
||||||
struct wl_client *client,
|
struct wl_client *client,
|
||||||
struct wl_resource *seat_resource,
|
struct wl_resource *seat_resource,
|
||||||
@@ -127,4 +138,8 @@ gboolean meta_wayland_pointer_can_popup (MetaWaylandPointer *pointer,
|
|||||||
|
|
||||||
MetaWaylandSurface *meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer);
|
MetaWaylandSurface *meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer);
|
||||||
|
|
||||||
|
MetaWaylandPointerClient * meta_wayland_pointer_get_pointer_client (MetaWaylandPointer *pointer,
|
||||||
|
struct wl_client *client);
|
||||||
|
void meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resource);
|
||||||
|
|
||||||
#endif /* META_WAYLAND_POINTER_H */
|
#endif /* META_WAYLAND_POINTER_H */
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include "meta-wayland-versions.h"
|
#include "meta-wayland-versions.h"
|
||||||
#include "meta-wayland-surface.h"
|
#include "meta-wayland-surface.h"
|
||||||
#include "meta-wayland-seat.h"
|
#include "meta-wayland-seat.h"
|
||||||
|
#include "meta-wayland-pointer-gestures.h"
|
||||||
|
|
||||||
typedef struct _MetaXWaylandSelection MetaXWaylandSelection;
|
typedef struct _MetaXWaylandSelection MetaXWaylandSelection;
|
||||||
|
|
||||||
|
@@ -332,6 +332,8 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
|||||||
case CLUTTER_BUTTON_PRESS:
|
case CLUTTER_BUTTON_PRESS:
|
||||||
case CLUTTER_BUTTON_RELEASE:
|
case CLUTTER_BUTTON_RELEASE:
|
||||||
case CLUTTER_SCROLL:
|
case CLUTTER_SCROLL:
|
||||||
|
case CLUTTER_TOUCHPAD_SWIPE:
|
||||||
|
case CLUTTER_TOUCHPAD_PINCH:
|
||||||
return meta_wayland_pointer_handle_event (&seat->pointer, event);
|
return meta_wayland_pointer_handle_event (&seat->pointer, event);
|
||||||
|
|
||||||
case CLUTTER_KEY_PRESS:
|
case CLUTTER_KEY_PRESS:
|
||||||
@@ -370,15 +372,6 @@ meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat,
|
|||||||
meta_wayland_data_device_set_keyboard_focus (&seat->data_device);
|
meta_wayland_data_device_set_keyboard_focus (&seat->data_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat)
|
|
||||||
{
|
|
||||||
if ((seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
meta_wayland_pointer_update_cursor_surface (&seat->pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
meta_wayland_seat_get_grab_info (MetaWaylandSeat *seat,
|
meta_wayland_seat_get_grab_info (MetaWaylandSeat *seat,
|
||||||
MetaWaylandSurface *surface,
|
MetaWaylandSurface *surface,
|
||||||
|
@@ -58,7 +58,6 @@ void meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat,
|
|||||||
MetaWaylandSurface *surface);
|
MetaWaylandSurface *surface);
|
||||||
|
|
||||||
void meta_wayland_seat_repick (MetaWaylandSeat *seat);
|
void meta_wayland_seat_repick (MetaWaylandSeat *seat);
|
||||||
void meta_wayland_seat_update_cursor_surface (MetaWaylandSeat *seat);
|
|
||||||
|
|
||||||
gboolean meta_wayland_seat_get_grab_info (MetaWaylandSeat *seat,
|
gboolean meta_wayland_seat_get_grab_info (MetaWaylandSeat *seat,
|
||||||
MetaWaylandSurface *surface,
|
MetaWaylandSurface *surface,
|
||||||
|
@@ -55,6 +55,11 @@
|
|||||||
#include "meta-surface-actor-wayland.h"
|
#include "meta-surface-actor-wayland.h"
|
||||||
#include "meta-xwayland-private.h"
|
#include "meta-xwayland-private.h"
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandSurfaceRolePrivate
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface;
|
||||||
|
} MetaWaylandSurfaceRolePrivate;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
|
META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE,
|
||||||
@@ -68,24 +73,100 @@ typedef struct
|
|||||||
struct wl_listener sibling_destroy_listener;
|
struct wl_listener sibling_destroy_listener;
|
||||||
} MetaWaylandSubsurfacePlacementOp;
|
} MetaWaylandSubsurfacePlacementOp;
|
||||||
|
|
||||||
int
|
GType meta_wayland_surface_get_type (void) G_GNUC_CONST;
|
||||||
meta_wayland_surface_set_role (MetaWaylandSurface *surface,
|
|
||||||
MetaWaylandSurfaceRole role,
|
G_DEFINE_TYPE (MetaWaylandSurface, meta_wayland_surface, G_TYPE_OBJECT);
|
||||||
struct wl_resource *error_resource,
|
|
||||||
uint32_t error_code)
|
GType meta_wayland_surface_role_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole,
|
||||||
|
meta_wayland_surface_role,
|
||||||
|
G_TYPE_OBJECT);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleSubsurface
|
||||||
{
|
{
|
||||||
if (surface->role == META_WAYLAND_SURFACE_ROLE_NONE ||
|
MetaWaylandSurfaceRole parent;
|
||||||
surface->role == role)
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_subsurface_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleSubsurface,
|
||||||
|
meta_wayland_surface_role_subsurface,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleXdgSurface
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_xdg_surface_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleXdgSurface,
|
||||||
|
meta_wayland_surface_role_xdg_surface,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleXdgPopup
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_xdg_popup_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleXdgPopup,
|
||||||
|
meta_wayland_surface_role_xdg_popup,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleWlShellSurface
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_wl_shell_surface_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleWlShellSurface,
|
||||||
|
meta_wayland_surface_role_wl_shell_surface,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleDND
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_dnd_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleDND,
|
||||||
|
meta_wayland_surface_role_dnd,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role);
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaWaylandPendingState *pending);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_wayland_surface_role_is_on_output (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaMonitorInfo *info);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
|
||||||
|
GType role_type)
|
||||||
|
{
|
||||||
|
if (!surface->role)
|
||||||
{
|
{
|
||||||
surface->role = role;
|
MetaWaylandSurfaceRolePrivate *role_priv;
|
||||||
return 0;
|
|
||||||
|
surface->role = g_object_new (role_type, NULL);
|
||||||
|
role_priv =
|
||||||
|
meta_wayland_surface_role_get_instance_private (surface->role);
|
||||||
|
role_priv->surface = surface;
|
||||||
|
|
||||||
|
meta_wayland_surface_role_assigned (surface->role);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (G_OBJECT_TYPE (surface->role) != role_type)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wl_resource_post_error (error_resource, error_code,
|
return TRUE;
|
||||||
"wl_surface@%d already has a different role",
|
|
||||||
wl_resource_get_id (surface->resource));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,18 +248,24 @@ surface_process_damage (MetaWaylandSurface *surface,
|
|||||||
cairo_region_destroy (scaled_region);
|
cairo_region_destroy (scaled_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
cursor_surface_commit (MetaWaylandSurface *surface,
|
meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface,
|
||||||
MetaWaylandPendingState *pending)
|
MetaWaylandPendingState *pending)
|
||||||
{
|
{
|
||||||
if (pending->newly_attached)
|
wl_list_insert_list (&surface->compositor->frame_callbacks,
|
||||||
meta_wayland_seat_update_cursor_surface (surface->compositor->seat);
|
&pending->frame_callback_list);
|
||||||
|
wl_list_init (&pending->frame_callback_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dnd_surface_commit (MetaWaylandSurface *surface,
|
dnd_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
MetaWaylandPendingState *pending)
|
MetaWaylandPendingState *pending)
|
||||||
{
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
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);
|
meta_wayland_data_device_update_dnd_surface (&surface->compositor->seat->data_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,12 +322,28 @@ destroy_window (MetaWaylandSurface *surface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
toplevel_surface_commit (MetaWaylandSurface *surface,
|
queue_surface_actor_frame_callbacks (MetaWaylandSurface *surface,
|
||||||
|
MetaWaylandPendingState *pending)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorWayland *surface_actor =
|
||||||
|
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
|
||||||
|
|
||||||
|
meta_surface_actor_wayland_add_frame_callbacks (surface_actor,
|
||||||
|
&pending->frame_callback_list);
|
||||||
|
wl_list_init (&pending->frame_callback_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
MetaWaylandPendingState *pending)
|
MetaWaylandPendingState *pending)
|
||||||
{
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
MetaWindow *window = surface->window;
|
MetaWindow *window = surface->window;
|
||||||
|
|
||||||
if (surface->role == META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE)
|
queue_surface_actor_frame_callbacks (surface, pending);
|
||||||
|
|
||||||
|
if (META_IS_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (surface->role))
|
||||||
{
|
{
|
||||||
/* For wl_shell, it's equivalent to an unmap. Semantics
|
/* For wl_shell, it's equivalent to an unmap. Semantics
|
||||||
* are poorly defined, so we can choose some that are
|
* are poorly defined, so we can choose some that are
|
||||||
@@ -256,6 +359,12 @@ toplevel_surface_commit (MetaWaylandSurface *surface,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (META_IS_WAYLAND_SURFACE_ROLE_XDG_POPUP (surface->role))
|
||||||
|
{
|
||||||
|
/* Ignore commits if we couldn't grab the pointer */
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (surface->buffer == NULL)
|
if (surface->buffer == NULL)
|
||||||
@@ -268,6 +377,8 @@ toplevel_surface_commit (MetaWaylandSurface *surface,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_assert (window != NULL);
|
||||||
|
|
||||||
/* We resize X based surfaces according to X events */
|
/* We resize X based surfaces according to X events */
|
||||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||||
{
|
{
|
||||||
@@ -332,7 +443,9 @@ pending_state_init (MetaWaylandPendingState *state)
|
|||||||
state->scale = 0;
|
state->scale = 0;
|
||||||
|
|
||||||
state->input_region = NULL;
|
state->input_region = NULL;
|
||||||
|
state->input_region_set = FALSE;
|
||||||
state->opaque_region = NULL;
|
state->opaque_region = NULL;
|
||||||
|
state->opaque_region_set = FALSE;
|
||||||
|
|
||||||
state->damage = cairo_region_create ();
|
state->damage = cairo_region_create ();
|
||||||
state->buffer_destroy_listener.notify = surface_handle_pending_buffer_destroy;
|
state->buffer_destroy_listener.notify = surface_handle_pending_buffer_destroy;
|
||||||
@@ -382,12 +495,16 @@ move_pending_state (MetaWaylandPendingState *from,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
subsurface_surface_commit (MetaWaylandSurface *surface,
|
subsurface_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
MetaWaylandPendingState *pending)
|
MetaWaylandPendingState *pending)
|
||||||
{
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
MetaSurfaceActorWayland *surface_actor =
|
MetaSurfaceActorWayland *surface_actor =
|
||||||
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
|
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
|
||||||
|
|
||||||
|
queue_surface_actor_frame_callbacks (surface, pending);
|
||||||
|
|
||||||
if (surface->buffer != NULL)
|
if (surface->buffer != NULL)
|
||||||
clutter_actor_show (CLUTTER_ACTOR (surface_actor));
|
clutter_actor_show (CLUTTER_ACTOR (surface_actor));
|
||||||
else
|
else
|
||||||
@@ -485,8 +602,6 @@ static void
|
|||||||
apply_pending_state (MetaWaylandSurface *surface,
|
apply_pending_state (MetaWaylandSurface *surface,
|
||||||
MetaWaylandPendingState *pending)
|
MetaWaylandPendingState *pending)
|
||||||
{
|
{
|
||||||
MetaWaylandCompositor *compositor = surface->compositor;
|
|
||||||
|
|
||||||
if (pending->newly_attached)
|
if (pending->newly_attached)
|
||||||
{
|
{
|
||||||
if (!surface->buffer && surface->window)
|
if (!surface->buffer && surface->window)
|
||||||
@@ -510,42 +625,40 @@ apply_pending_state (MetaWaylandSurface *surface,
|
|||||||
surface->offset_x += pending->dx;
|
surface->offset_x += pending->dx;
|
||||||
surface->offset_y += pending->dy;
|
surface->offset_y += pending->dy;
|
||||||
|
|
||||||
if (pending->opaque_region)
|
if (pending->opaque_region_set)
|
||||||
{
|
{
|
||||||
if (surface->opaque_region)
|
if (surface->opaque_region)
|
||||||
cairo_region_destroy (surface->opaque_region);
|
cairo_region_destroy (surface->opaque_region);
|
||||||
surface->opaque_region = cairo_region_reference (pending->opaque_region);
|
if (pending->opaque_region)
|
||||||
|
surface->opaque_region = cairo_region_reference (pending->opaque_region);
|
||||||
|
else
|
||||||
|
surface->opaque_region = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pending->input_region)
|
if (pending->input_region_set)
|
||||||
{
|
{
|
||||||
if (surface->input_region)
|
if (surface->input_region)
|
||||||
cairo_region_destroy (surface->input_region);
|
cairo_region_destroy (surface->input_region);
|
||||||
surface->input_region = cairo_region_reference (pending->input_region);
|
if (pending->input_region)
|
||||||
|
surface->input_region = cairo_region_reference (pending->input_region);
|
||||||
|
else
|
||||||
|
surface->input_region = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wl_surface.frame */
|
if (surface->role)
|
||||||
wl_list_insert_list (&compositor->frame_callbacks, &pending->frame_callback_list);
|
|
||||||
wl_list_init (&pending->frame_callback_list);
|
|
||||||
|
|
||||||
switch (surface->role)
|
|
||||||
{
|
{
|
||||||
case META_WAYLAND_SURFACE_ROLE_NONE:
|
meta_wayland_surface_role_commit (surface->role, pending);
|
||||||
break;
|
g_assert (wl_list_empty (&pending->frame_callback_list));
|
||||||
case META_WAYLAND_SURFACE_ROLE_CURSOR:
|
}
|
||||||
cursor_surface_commit (surface, pending);
|
else
|
||||||
break;
|
{
|
||||||
case META_WAYLAND_SURFACE_ROLE_DND:
|
/* Since there is no role assigned to the surface yet, keep frame
|
||||||
dnd_surface_commit (surface, pending);
|
* callbacks queued until a role is assigned and we know how
|
||||||
break;
|
* the surface will be drawn.
|
||||||
case META_WAYLAND_SURFACE_ROLE_XDG_SURFACE:
|
*/
|
||||||
case META_WAYLAND_SURFACE_ROLE_XDG_POPUP:
|
wl_list_insert_list (&surface->pending_frame_callback_list,
|
||||||
case META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE:
|
&pending->frame_callback_list);
|
||||||
toplevel_surface_commit (surface, pending);
|
wl_list_init (&pending->frame_callback_list);
|
||||||
break;
|
|
||||||
case META_WAYLAND_SURFACE_ROLE_SUBSURFACE:
|
|
||||||
subsurface_surface_commit (surface, pending);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
meta_surface_actor_wayland_sync_state (
|
meta_surface_actor_wayland_sync_state (
|
||||||
@@ -678,6 +791,7 @@ wl_surface_set_opaque_region (struct wl_client *client,
|
|||||||
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -698,6 +812,7 @@ wl_surface_set_input_region (struct wl_client *client,
|
|||||||
cairo_region_t *cr_region = meta_wayland_region_peek_cairo_region (region);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -852,16 +967,28 @@ set_surface_is_on_output (MetaWaylandSurface *surface,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
actor_surface_is_on_output (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaMonitorInfo *monitor)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
MetaSurfaceActorWayland *actor =
|
||||||
|
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
|
||||||
|
|
||||||
|
return meta_surface_actor_wayland_is_on_monitor (actor, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
|
update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
|
||||||
{
|
{
|
||||||
MetaWaylandOutput *wayland_output = value;
|
MetaWaylandOutput *wayland_output = value;
|
||||||
MetaWaylandSurface *surface = user_data;
|
MetaWaylandSurface *surface = user_data;
|
||||||
MetaSurfaceActorWayland *actor =
|
|
||||||
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
|
|
||||||
MetaMonitorInfo *monitor;
|
MetaMonitorInfo *monitor;
|
||||||
gboolean is_on_output;
|
gboolean is_on_output;
|
||||||
|
|
||||||
|
g_assert (surface->role);
|
||||||
|
|
||||||
monitor = wayland_output->monitor_info;
|
monitor = wayland_output->monitor_info;
|
||||||
if (!monitor)
|
if (!monitor)
|
||||||
{
|
{
|
||||||
@@ -869,7 +996,7 @@ update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_on_output = meta_surface_actor_wayland_is_on_monitor (actor, monitor);
|
is_on_output = meta_wayland_surface_role_is_on_output (surface->role, monitor);
|
||||||
set_surface_is_on_output (surface, wayland_output, is_on_output);
|
set_surface_is_on_output (surface, wayland_output, is_on_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,6 +1025,9 @@ wl_surface_destructor (struct wl_resource *resource)
|
|||||||
{
|
{
|
||||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||||
MetaWaylandCompositor *compositor = surface->compositor;
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
MetaWaylandFrameCallback *cb, *next;
|
||||||
|
|
||||||
|
g_clear_object (&surface->role);
|
||||||
|
|
||||||
/* If we still have a window at the time of destruction, that means that
|
/* If we still have a window at the time of destruction, that means that
|
||||||
* the client is disconnecting, as the resources are destroyed in a random
|
* the client is disconnecting, as the resources are destroyed in a random
|
||||||
@@ -922,6 +1052,9 @@ wl_surface_destructor (struct wl_resource *resource)
|
|||||||
|
|
||||||
g_hash_table_unref (surface->outputs);
|
g_hash_table_unref (surface->outputs);
|
||||||
|
|
||||||
|
wl_list_for_each_safe (cb, next, &surface->pending_frame_callback_list, link)
|
||||||
|
wl_resource_destroy (cb->resource);
|
||||||
|
|
||||||
if (surface->resource)
|
if (surface->resource)
|
||||||
wl_resource_set_user_data (surface->resource, NULL);
|
wl_resource_set_user_data (surface->resource, NULL);
|
||||||
|
|
||||||
@@ -936,7 +1069,7 @@ wl_surface_destructor (struct wl_resource *resource)
|
|||||||
if (surface->gtk_surface)
|
if (surface->gtk_surface)
|
||||||
wl_resource_destroy (surface->gtk_surface);
|
wl_resource_destroy (surface->gtk_surface);
|
||||||
|
|
||||||
g_slice_free (MetaWaylandSurface, surface);
|
g_object_unref (surface);
|
||||||
|
|
||||||
meta_wayland_compositor_repick (compositor);
|
meta_wayland_compositor_repick (compositor);
|
||||||
}
|
}
|
||||||
@@ -947,7 +1080,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
|||||||
struct wl_resource *compositor_resource,
|
struct wl_resource *compositor_resource,
|
||||||
guint32 id)
|
guint32 id)
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *surface = g_slice_new0 (MetaWaylandSurface);
|
MetaWaylandSurface *surface = g_object_new (META_TYPE_WAYLAND_SURFACE, NULL);
|
||||||
|
|
||||||
surface->compositor = compositor;
|
surface->compositor = compositor;
|
||||||
surface->scale = 1;
|
surface->scale = 1;
|
||||||
@@ -958,6 +1091,8 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
|
|||||||
surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy;
|
surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy;
|
||||||
surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface));
|
surface->surface_actor = g_object_ref_sink (meta_surface_actor_wayland_new (surface));
|
||||||
|
|
||||||
|
wl_list_init (&surface->pending_frame_callback_list);
|
||||||
|
|
||||||
sync_drag_dest_funcs (surface);
|
sync_drag_dest_funcs (surface);
|
||||||
|
|
||||||
surface->outputs = g_hash_table_new (NULL, NULL);
|
surface->outputs = g_hash_table_new (NULL, NULL);
|
||||||
@@ -1247,11 +1382,14 @@ xdg_shell_get_xdg_surface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta_wayland_surface_set_role (surface,
|
if (!meta_wayland_surface_assign_role (surface,
|
||||||
META_WAYLAND_SURFACE_ROLE_XDG_SURFACE,
|
META_TYPE_WAYLAND_SURFACE_ROLE_XDG_SURFACE))
|
||||||
surface_resource,
|
{
|
||||||
XDG_SHELL_ERROR_ROLE) != 0)
|
wl_resource_post_error (resource, XDG_SHELL_ERROR_ROLE,
|
||||||
return;
|
"wl_surface@%d already has a different role",
|
||||||
|
wl_resource_get_id (surface->resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
surface->xdg_surface = wl_resource_create (client, &xdg_surface_interface, wl_resource_get_version (resource), id);
|
surface->xdg_surface = wl_resource_create (client, &xdg_surface_interface, wl_resource_get_version (resource), id);
|
||||||
wl_resource_set_implementation (surface->xdg_surface, &meta_wayland_xdg_surface_interface, surface, xdg_surface_destructor);
|
wl_resource_set_implementation (surface->xdg_surface, &meta_wayland_xdg_surface_interface, surface, xdg_surface_destructor);
|
||||||
@@ -1347,9 +1485,6 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
|
|||||||
MetaDisplay *display = meta_get_display ();
|
MetaDisplay *display = meta_get_display ();
|
||||||
MetaWaylandPopup *popup;
|
MetaWaylandPopup *popup;
|
||||||
|
|
||||||
if (parent_surf == NULL || parent_surf->window == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (surface->xdg_popup != NULL)
|
if (surface->xdg_popup != NULL)
|
||||||
{
|
{
|
||||||
wl_resource_post_error (surface_resource,
|
wl_resource_post_error (surface_resource,
|
||||||
@@ -1358,13 +1493,18 @@ xdg_shell_get_xdg_popup (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta_wayland_surface_set_role (surface,
|
if (!meta_wayland_surface_assign_role (surface,
|
||||||
META_WAYLAND_SURFACE_ROLE_XDG_POPUP,
|
META_TYPE_WAYLAND_SURFACE_ROLE_XDG_POPUP))
|
||||||
surface_resource,
|
{
|
||||||
XDG_SHELL_ERROR_ROLE) != 0)
|
wl_resource_post_error (resource, XDG_SHELL_ERROR_ROLE,
|
||||||
return;
|
"wl_surface@%d already has a different role",
|
||||||
|
wl_resource_get_id (surface->resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (parent_surf->xdg_popup == NULL && parent_surf->xdg_surface == NULL)
|
if (parent_surf == NULL ||
|
||||||
|
parent_surf->window == NULL ||
|
||||||
|
(parent_surf->xdg_popup == NULL && parent_surf->xdg_surface == NULL))
|
||||||
{
|
{
|
||||||
wl_resource_post_error (resource,
|
wl_resource_post_error (resource,
|
||||||
XDG_POPUP_ERROR_INVALID_PARENT,
|
XDG_POPUP_ERROR_INVALID_PARENT,
|
||||||
@@ -1696,11 +1836,14 @@ wl_shell_get_shell_surface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta_wayland_surface_set_role (surface,
|
if (!meta_wayland_surface_assign_role (surface,
|
||||||
META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE,
|
META_TYPE_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE))
|
||||||
surface_resource,
|
{
|
||||||
WL_SHELL_ERROR_ROLE) != 0)
|
wl_resource_post_error (resource, WL_SHELL_ERROR_ROLE,
|
||||||
return;
|
"wl_surface@%d already has a different role",
|
||||||
|
wl_resource_get_id (surface->resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id);
|
surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id);
|
||||||
wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor);
|
wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor);
|
||||||
@@ -2045,11 +2188,17 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta_wayland_surface_set_role (surface,
|
if (!meta_wayland_surface_assign_role (surface,
|
||||||
META_WAYLAND_SURFACE_ROLE_SUBSURFACE,
|
META_TYPE_WAYLAND_SURFACE_ROLE_SUBSURFACE))
|
||||||
surface_resource,
|
{
|
||||||
WL_SHELL_ERROR_ROLE) != 0)
|
/* FIXME: There is no subcompositor "role" error yet, so lets just use something
|
||||||
return;
|
* similar until there is.
|
||||||
|
*/
|
||||||
|
wl_resource_post_error (resource, WL_SHELL_ERROR_ROLE,
|
||||||
|
"wl_surface@%d already has a different role",
|
||||||
|
wl_resource_get_id (surface->resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
surface->wl_subsurface = wl_resource_create (client, &wl_subsurface_interface, wl_resource_get_version (resource), id);
|
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);
|
wl_resource_set_implementation (surface->wl_subsurface, &meta_wayland_wl_subsurface_interface, surface, wl_subsurface_destructor);
|
||||||
@@ -2259,3 +2408,168 @@ meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_init (MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_init (MetaWaylandSurfaceRole *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_class_init (MetaWaylandSurfaceRoleClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
|
||||||
|
{
|
||||||
|
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->assigned (surface_role);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaWaylandPendingState *pending)
|
||||||
|
{
|
||||||
|
META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->commit (surface_role,
|
||||||
|
pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_wayland_surface_role_is_on_output (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaMonitorInfo *monitor)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *klass;
|
||||||
|
|
||||||
|
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
|
||||||
|
if (klass->is_on_output)
|
||||||
|
return klass->is_on_output (surface_role, monitor);
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandSurface *
|
||||||
|
meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRolePrivate *priv =
|
||||||
|
meta_wayland_surface_role_get_instance_private (role);
|
||||||
|
|
||||||
|
return priv->surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
wl_list_insert_list (&surface->compositor->frame_callbacks,
|
||||||
|
&surface->pending_frame_callback_list);
|
||||||
|
wl_list_init (&surface->pending_frame_callback_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
default_role_assigned (MetaWaylandSurfaceRole *surface_role)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
|
||||||
|
meta_wayland_surface_queue_pending_frame_callbacks (surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
actor_surface_assigned (MetaWaylandSurfaceRole *surface_role)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
MetaSurfaceActorWayland *surface_actor =
|
||||||
|
META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
|
||||||
|
|
||||||
|
meta_surface_actor_wayland_add_frame_callbacks (surface_actor,
|
||||||
|
&surface->pending_frame_callback_list);
|
||||||
|
wl_list_init (&surface->pending_frame_callback_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_dnd_init (MetaWaylandSurfaceRoleDND *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_dnd_class_init (MetaWaylandSurfaceRoleDNDClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = default_role_assigned;
|
||||||
|
surface_role_class->commit = dnd_surface_commit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_xdg_surface_init (MetaWaylandSurfaceRoleXdgSurface *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_xdg_surface_class_init (MetaWaylandSurfaceRoleXdgSurfaceClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = actor_surface_assigned;
|
||||||
|
surface_role_class->commit = toplevel_surface_commit;
|
||||||
|
surface_role_class->is_on_output = actor_surface_is_on_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_xdg_popup_init (MetaWaylandSurfaceRoleXdgPopup *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_xdg_popup_class_init (MetaWaylandSurfaceRoleXdgPopupClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = actor_surface_assigned;
|
||||||
|
surface_role_class->commit = toplevel_surface_commit;
|
||||||
|
surface_role_class->is_on_output = actor_surface_is_on_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_wl_shell_surface_init (MetaWaylandSurfaceRoleWlShellSurface *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_wl_shell_surface_class_init (MetaWaylandSurfaceRoleWlShellSurfaceClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = actor_surface_assigned;
|
||||||
|
surface_role_class->commit = toplevel_surface_commit;
|
||||||
|
surface_role_class->is_on_output = actor_surface_is_on_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_subsurface_init (MetaWaylandSurfaceRoleSubsurface *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_subsurface_class_init (MetaWaylandSurfaceRoleSubsurfaceClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = actor_surface_assigned;
|
||||||
|
surface_role_class->commit = subsurface_surface_commit;
|
||||||
|
surface_role_class->is_on_output = actor_surface_is_on_output;
|
||||||
|
}
|
||||||
|
@@ -30,24 +30,67 @@
|
|||||||
#include <meta/meta-cursor-tracker.h>
|
#include <meta/meta-cursor-tracker.h>
|
||||||
#include "meta-wayland-types.h"
|
#include "meta-wayland-types.h"
|
||||||
#include "meta-surface-actor.h"
|
#include "meta-surface-actor.h"
|
||||||
|
#include "backends/meta-monitor-manager-private.h"
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandPendingState MetaWaylandPendingState;
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE (meta_wayland_surface_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurface,
|
||||||
|
meta_wayland_surface,
|
||||||
|
META, WAYLAND_SURFACE,
|
||||||
|
GObject);
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE_ROLE (meta_wayland_surface_role_get_type ())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRole, meta_wayland_surface_role,
|
||||||
|
META, WAYLAND_SURFACE_ROLE, GObject);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
void (*assigned) (MetaWaylandSurfaceRole *surface_role);
|
||||||
|
void (*commit) (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaWaylandPendingState *pending);
|
||||||
|
gboolean (*is_on_output) (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaMonitorInfo *monitor);
|
||||||
|
};
|
||||||
|
|
||||||
struct _MetaWaylandSerial {
|
struct _MetaWaylandSerial {
|
||||||
gboolean set;
|
gboolean set;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_SUBSURFACE (meta_wayland_surface_role_subsurface_get_type ())
|
||||||
{
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleSubsurface,
|
||||||
META_WAYLAND_SURFACE_ROLE_NONE,
|
meta_wayland_surface_role_subsurface,
|
||||||
META_WAYLAND_SURFACE_ROLE_SUBSURFACE,
|
META, WAYLAND_SURFACE_ROLE_SUBSURFACE,
|
||||||
META_WAYLAND_SURFACE_ROLE_XDG_SURFACE,
|
MetaWaylandSurfaceRole);
|
||||||
META_WAYLAND_SURFACE_ROLE_XDG_POPUP,
|
|
||||||
META_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE,
|
|
||||||
META_WAYLAND_SURFACE_ROLE_CURSOR,
|
|
||||||
META_WAYLAND_SURFACE_ROLE_DND,
|
|
||||||
} MetaWaylandSurfaceRole;
|
|
||||||
|
|
||||||
typedef struct
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_XDG_SURFACE (meta_wayland_surface_role_xdg_surface_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXdgSurface,
|
||||||
|
meta_wayland_surface_role_xdg_surface,
|
||||||
|
META, WAYLAND_SURFACE_ROLE_XDG_SURFACE,
|
||||||
|
MetaWaylandSurfaceRole);
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_XDG_POPUP (meta_wayland_surface_role_xdg_popup_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXdgPopup,
|
||||||
|
meta_wayland_surface_role_xdg_popup,
|
||||||
|
META, WAYLAND_SURFACE_ROLE_XDG_POPUP,
|
||||||
|
MetaWaylandSurfaceRole);
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (meta_wayland_surface_role_wl_shell_surface_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleWlShellSurface,
|
||||||
|
meta_wayland_surface_role_wl_shell_surface,
|
||||||
|
META, WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE,
|
||||||
|
MetaWaylandSurfaceRole);
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_DND (meta_wayland_surface_role_dnd_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleDND,
|
||||||
|
meta_wayland_surface_role_dnd,
|
||||||
|
META, WAYLAND_SURFACE_ROLE_DND,
|
||||||
|
MetaWaylandSurfaceRole);
|
||||||
|
|
||||||
|
struct _MetaWaylandPendingState
|
||||||
{
|
{
|
||||||
/* wl_surface.attach */
|
/* wl_surface.attach */
|
||||||
gboolean newly_attached;
|
gboolean newly_attached;
|
||||||
@@ -62,14 +105,16 @@ typedef struct
|
|||||||
cairo_region_t *damage;
|
cairo_region_t *damage;
|
||||||
|
|
||||||
cairo_region_t *input_region;
|
cairo_region_t *input_region;
|
||||||
|
gboolean input_region_set;
|
||||||
cairo_region_t *opaque_region;
|
cairo_region_t *opaque_region;
|
||||||
|
gboolean opaque_region_set;
|
||||||
|
|
||||||
/* wl_surface.frame */
|
/* wl_surface.frame */
|
||||||
struct wl_list frame_callback_list;
|
struct wl_list frame_callback_list;
|
||||||
|
|
||||||
MetaRectangle new_geometry;
|
MetaRectangle new_geometry;
|
||||||
gboolean has_new_geometry;
|
gboolean has_new_geometry;
|
||||||
} MetaWaylandPendingState;
|
};
|
||||||
|
|
||||||
struct _MetaWaylandDragDestFuncs
|
struct _MetaWaylandDragDestFuncs
|
||||||
{
|
{
|
||||||
@@ -87,11 +132,13 @@ struct _MetaWaylandDragDestFuncs
|
|||||||
|
|
||||||
struct _MetaWaylandSurface
|
struct _MetaWaylandSurface
|
||||||
{
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
/* Generic stuff */
|
/* Generic stuff */
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
MetaWaylandCompositor *compositor;
|
MetaWaylandCompositor *compositor;
|
||||||
MetaSurfaceActor *surface_actor;
|
MetaSurfaceActor *surface_actor;
|
||||||
MetaWaylandSurfaceRole role;
|
MetaWaylandSurfaceRole *role;
|
||||||
MetaWindow *window;
|
MetaWindow *window;
|
||||||
MetaWaylandBuffer *buffer;
|
MetaWaylandBuffer *buffer;
|
||||||
struct wl_listener buffer_destroy_listener;
|
struct wl_listener buffer_destroy_listener;
|
||||||
@@ -102,6 +149,11 @@ struct _MetaWaylandSurface
|
|||||||
GList *subsurfaces;
|
GList *subsurfaces;
|
||||||
GHashTable *outputs;
|
GHashTable *outputs;
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
struct wl_list pending_frame_callback_list;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
const MetaWaylandDragDestFuncs *funcs;
|
const MetaWaylandDragDestFuncs *funcs;
|
||||||
} dnd;
|
} dnd;
|
||||||
@@ -164,10 +216,8 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
|
|||||||
struct wl_resource *compositor_resource,
|
struct wl_resource *compositor_resource,
|
||||||
guint32 id);
|
guint32 id);
|
||||||
|
|
||||||
int meta_wayland_surface_set_role (MetaWaylandSurface *surface,
|
gboolean meta_wayland_surface_assign_role (MetaWaylandSurface *surface,
|
||||||
MetaWaylandSurfaceRole role,
|
GType role_type);
|
||||||
struct wl_resource *error_resource,
|
|
||||||
uint32_t error_code);
|
|
||||||
|
|
||||||
void meta_wayland_surface_set_window (MetaWaylandSurface *surface,
|
void meta_wayland_surface_set_window (MetaWaylandSurface *surface,
|
||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
@@ -195,4 +245,11 @@ void meta_wayland_surface_update_outputs (MetaWaylandSurface *sur
|
|||||||
|
|
||||||
MetaWindow * meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface);
|
MetaWindow * meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface);
|
||||||
|
|
||||||
|
void meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface);
|
||||||
|
|
||||||
|
void meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface,
|
||||||
|
MetaWaylandPendingState *pending);
|
||||||
|
|
||||||
|
MetaWaylandSurface * meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -43,4 +43,6 @@ typedef struct _MetaWaylandOutput MetaWaylandOutput;
|
|||||||
|
|
||||||
typedef struct _MetaWaylandSerial MetaWaylandSerial;
|
typedef struct _MetaWaylandSerial MetaWaylandSerial;
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandPointerClient MetaWaylandPointerClient;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -44,5 +44,6 @@
|
|||||||
#define META_XSERVER_VERSION 1
|
#define META_XSERVER_VERSION 1
|
||||||
#define META_GTK_SHELL_VERSION 2
|
#define META_GTK_SHELL_VERSION 2
|
||||||
#define META_WL_SUBCOMPOSITOR_VERSION 1
|
#define META_WL_SUBCOMPOSITOR_VERSION 1
|
||||||
|
#define META__WL_POINTER_GESTURES_VERSION 1
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -207,6 +207,28 @@ meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
|||||||
return meta_wayland_seat_handle_event (compositor->seat, event);
|
return meta_wayland_seat_handle_event (compositor->seat, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* meta_wayland_compositor_update_key_state:
|
||||||
|
* @compositor: the #MetaWaylandCompositor
|
||||||
|
* @key_vector: bit vector of key states
|
||||||
|
* @key_vector_len: length of @key_vector
|
||||||
|
* @offset: the key for the first evdev keycode is found at this offset in @key_vector
|
||||||
|
*
|
||||||
|
* This function is used to resynchronize the key state that Mutter
|
||||||
|
* is tracking with the actual keyboard state. This is useful, for example,
|
||||||
|
* to handle changes in key state when a nested compositor doesn't
|
||||||
|
* have focus. We need to fix up the XKB modifier tracking and deliver
|
||||||
|
* any modifier changes to clients.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
|
||||||
|
char *key_vector,
|
||||||
|
int key_vector_len,
|
||||||
|
int offset)
|
||||||
|
{
|
||||||
|
meta_wayland_keyboard_update_key_state (&compositor->seat->keyboard,
|
||||||
|
key_vector, key_vector_len, offset);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
|
meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
|
||||||
MetaWaylandSurface *surface)
|
MetaWaylandSurface *surface)
|
||||||
@@ -310,6 +332,7 @@ meta_wayland_init (void)
|
|||||||
meta_wayland_outputs_init (compositor);
|
meta_wayland_outputs_init (compositor);
|
||||||
meta_wayland_data_device_manager_init (compositor);
|
meta_wayland_data_device_manager_init (compositor);
|
||||||
meta_wayland_shell_init (compositor);
|
meta_wayland_shell_init (compositor);
|
||||||
|
meta_wayland_pointer_gestures_init (compositor);
|
||||||
meta_wayland_seat_init (compositor);
|
meta_wayland_seat_init (compositor);
|
||||||
|
|
||||||
compositor->display_name = wl_display_add_socket_auto (compositor->wayland_display);
|
compositor->display_name = wl_display_add_socket_auto (compositor->wayland_display);
|
||||||
|
@@ -39,6 +39,10 @@ void meta_wayland_compositor_update (MetaWaylandComp
|
|||||||
const ClutterEvent *event);
|
const ClutterEvent *event);
|
||||||
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
||||||
const ClutterEvent *event);
|
const ClutterEvent *event);
|
||||||
|
void meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
|
||||||
|
char *key_vector,
|
||||||
|
int key_vector_len,
|
||||||
|
int offset);
|
||||||
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
|
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
||||||
|
@@ -66,7 +66,7 @@ meta_window_wayland_manage (MetaWindow *window)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window->surface->role == META_WAYLAND_SURFACE_ROLE_XDG_POPUP)
|
if (META_IS_WAYLAND_SURFACE_ROLE_XDG_POPUP (window->surface->role))
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *parent = window->surface->popup.parent;
|
MetaWaylandSurface *parent = window->surface->popup.parent;
|
||||||
|
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include <gio/gunixinputstream.h>
|
#include <gio/gunixinputstream.h>
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/extensions/Xfixes.h>
|
||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
#include "meta-xwayland-private.h"
|
#include "meta-xwayland-private.h"
|
||||||
#include "meta-xwayland-selection-private.h"
|
#include "meta-xwayland-selection-private.h"
|
||||||
|
@@ -32,6 +32,24 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include "compositor/meta-surface-actor-wayland.h"
|
||||||
|
|
||||||
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_XWAYLAND (meta_wayland_surface_role_xwayland_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXWayland,
|
||||||
|
meta_wayland_surface_role_xwayland,
|
||||||
|
META, WAYLAND_SURFACE_ROLE_XWAYLAND,
|
||||||
|
MetaWaylandSurfaceRole);
|
||||||
|
|
||||||
|
struct _MetaWaylandSurfaceRoleXWayland
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType meta_wayland_surface_role_xwayland_get_type (void) G_GNUC_CONST;
|
||||||
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleXWayland,
|
||||||
|
meta_wayland_surface_role_xwayland,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
associate_window_with_surface (MetaWindow *window,
|
associate_window_with_surface (MetaWindow *window,
|
||||||
MetaWaylandSurface *surface)
|
MetaWaylandSurface *surface)
|
||||||
@@ -45,6 +63,16 @@ associate_window_with_surface (MetaWindow *window,
|
|||||||
if (window->surface)
|
if (window->surface)
|
||||||
window->surface->window = NULL;
|
window->surface->window = NULL;
|
||||||
|
|
||||||
|
if (!meta_wayland_surface_assign_role (surface,
|
||||||
|
META_TYPE_WAYLAND_SURFACE_ROLE_XWAYLAND))
|
||||||
|
{
|
||||||
|
wl_resource_post_error (surface->resource,
|
||||||
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
||||||
|
"wl_surface@%d already has a different role",
|
||||||
|
wl_resource_get_id (surface->resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
meta_wayland_surface_set_window (surface, window);
|
meta_wayland_surface_set_window (surface, window);
|
||||||
window->surface = surface;
|
window->surface = surface;
|
||||||
|
|
||||||
@@ -543,3 +571,53 @@ meta_xwayland_stop (MetaXWaylandManager *manager)
|
|||||||
g_clear_pointer (&manager->lock_file, g_free);
|
g_clear_pointer (&manager->lock_file, g_free);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xwayland_surface_assigned (MetaWaylandSurfaceRole *surface_role)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
|
||||||
|
/* See comment in xwayland_surface_commit for why we reply even though the
|
||||||
|
* surface may not be drawn the next frame.
|
||||||
|
*/
|
||||||
|
wl_list_insert_list (&surface->compositor->frame_callbacks,
|
||||||
|
&surface->pending_frame_callback_list);
|
||||||
|
wl_list_init (&surface->pending_frame_callback_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xwayland_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
||||||
|
MetaWaylandPendingState *pending)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface =
|
||||||
|
meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
|
||||||
|
/* For Xwayland windows, throttling frames when the window isn't actually
|
||||||
|
* drawn is less useful, because Xwayland still has to do the drawing sent
|
||||||
|
* from the application - the throttling would only be of sending us damage
|
||||||
|
* messages, so we simplify and send frame callbacks after the next paint of
|
||||||
|
* the screen, whether the window was drawn or not.
|
||||||
|
*
|
||||||
|
* Currently it may take a few frames before we draw the window, for not
|
||||||
|
* completely understood reasons, and in that case, not thottling frame
|
||||||
|
* callbacks to drawing has the happy side effect that we avoid showing the
|
||||||
|
* user the initial black frame from when the window is mapped empty.
|
||||||
|
*/
|
||||||
|
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_xwayland_init (MetaWaylandSurfaceRoleXWayland *role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_surface_role_xwayland_class_init (MetaWaylandSurfaceRoleXWaylandClass *klass)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
||||||
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
||||||
|
|
||||||
|
surface_role_class->assigned = xwayland_surface_assigned;
|
||||||
|
surface_role_class->commit = xwayland_surface_commit;
|
||||||
|
}
|
||||||
|
176
src/wayland/protocol/pointer-gestures.xml
Normal file
176
src/wayland/protocol/pointer-gestures.xml
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
<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>
|
@@ -31,6 +31,7 @@
|
|||||||
#include "group-props.h"
|
#include "group-props.h"
|
||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
#include <meta/window.h>
|
#include <meta/window.h>
|
||||||
|
#include <X11/Xlib-xcb.h>
|
||||||
|
|
||||||
static MetaGroup*
|
static MetaGroup*
|
||||||
meta_group_new (MetaDisplay *display,
|
meta_group_new (MetaDisplay *display,
|
||||||
@@ -50,10 +51,18 @@ meta_group_new (MetaDisplay *display,
|
|||||||
group->group_leader = group_leader;
|
group->group_leader = group_leader;
|
||||||
group->refcount = 1; /* owned by caller, hash table has only weak ref */
|
group->refcount = 1; /* owned by caller, hash table has only weak ref */
|
||||||
|
|
||||||
XWindowAttributes attrs;
|
xcb_connection_t *xcb_conn = XGetXCBConnection (display->xdisplay);
|
||||||
XGetWindowAttributes (display->xdisplay, group_leader, &attrs);
|
xcb_generic_error_t *e;
|
||||||
XSelectInput (display->xdisplay, group_leader,
|
g_autofree xcb_get_window_attributes_reply_t *attrs =
|
||||||
attrs.your_event_mask | PropertyChangeMask);
|
xcb_get_window_attributes_reply (xcb_conn,
|
||||||
|
xcb_get_window_attributes (xcb_conn, group_leader),
|
||||||
|
&e);
|
||||||
|
if (e)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const uint32_t events[] = { attrs->your_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||||
|
xcb_change_window_attributes (xcb_conn, group_leader,
|
||||||
|
XCB_CW_EVENT_MASK, events);
|
||||||
|
|
||||||
if (display->groups_by_leader == NULL)
|
if (display->groups_by_leader == NULL)
|
||||||
display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash,
|
display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash,
|
||||||
@@ -173,12 +182,14 @@ meta_window_compute_group (MetaWindow* window)
|
|||||||
window->group = group;
|
window->group = group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!window->group)
|
||||||
|
return;
|
||||||
|
|
||||||
window->group->windows = g_slist_prepend (window->group->windows, window);
|
window->group->windows = g_slist_prepend (window->group->windows, window);
|
||||||
|
|
||||||
meta_topic (META_DEBUG_GROUPS,
|
meta_topic (META_DEBUG_GROUPS,
|
||||||
"Adding %s to group with leader 0x%lx\n",
|
"Adding %s to group with leader 0x%lx\n",
|
||||||
window->desc, group->group_leader);
|
window->desc, group->group_leader);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -810,7 +810,10 @@ reload_net_wm_state (MetaWindow *window,
|
|||||||
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER)
|
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER)
|
||||||
priv->wm_state_skip_pager = TRUE;
|
priv->wm_state_skip_pager = TRUE;
|
||||||
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN)
|
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN)
|
||||||
window->fullscreen_after_placement = TRUE;
|
{
|
||||||
|
window->fullscreen = TRUE;
|
||||||
|
g_object_notify (G_OBJECT (window), "fullscreen");
|
||||||
|
}
|
||||||
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE)
|
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE)
|
||||||
window->wm_state_above = TRUE;
|
window->wm_state_above = TRUE;
|
||||||
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_BELOW)
|
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_BELOW)
|
||||||
|
Reference in New Issue
Block a user