Compare commits
464 Commits
wip/gestur
...
3.13.92
Author | SHA1 | Date | |
---|---|---|---|
2e06a6765c | |||
b63291069d | |||
f10cb02cbf | |||
276df8f18d | |||
d61dde12cb | |||
c8cc4344f2 | |||
ae292c856b | |||
35dd1e644d | |||
be85ead2f8 | |||
5c40345128 | |||
43b3573c51 | |||
ac6ec168da | |||
dbb7b9e85b | |||
1de740955f | |||
21f123c69f | |||
d6624b0a75 | |||
9c465a2d5a | |||
e53456d87c | |||
5716fc4b90 | |||
e926ebafdb | |||
7125b801f2 | |||
d20dae3553 | |||
73a47cec2a | |||
514d3b4bde | |||
6910ab5389 | |||
4052b0f048 | |||
493c0f71d2 | |||
ab40dfdd51 | |||
52678c39e6 | |||
a676249c0c | |||
2833c702c6 | |||
611f6741c2 | |||
df2587a61c | |||
30e7044746 | |||
458953268b | |||
1c227baf81 | |||
892699da73 | |||
f163a15b13 | |||
87779ed34e | |||
04bc846ef3 | |||
301acac163 | |||
9401196e88 | |||
3457366066 | |||
cb66cf6398 | |||
73573a85de | |||
b49a4ae0bc | |||
2f63c39fa6 | |||
95d9a95b2b | |||
44ecb1c050 | |||
0706de5378 | |||
9dd9938c38 | |||
e27bbdc769 | |||
09b46029fa | |||
5c289b7eab | |||
656573c5d2 | |||
59c5ac0cb5 | |||
53092424e6 | |||
6ba0491adf | |||
e3fb9e4cee | |||
8d53ae894b | |||
d50f8afa9e | |||
98fa343588 | |||
9ceb3fbb9a | |||
22d95546a7 | |||
33689ec558 | |||
602dd7fdf2 | |||
7f15c995b7 | |||
9be3e56b70 | |||
24119b8a9c | |||
4d75de006c | |||
e19516ec5a | |||
1ed607f398 | |||
7e0822c5b1 | |||
037c3438a3 | |||
cde5d4acfa | |||
d79db68bf8 | |||
b3b9d9e161 | |||
3f1f1645c7 | |||
18a82688e2 | |||
27d6b2645e | |||
fee40353e2 | |||
659360d543 | |||
3ea6424b8f | |||
96bee8e60d | |||
883c4a7b0f | |||
d4317ba1e4 | |||
9d69b2a963 | |||
ef3b000050 | |||
a4a688ed83 | |||
17dc5c57dd | |||
ef5f939db8 | |||
cb4751da4c | |||
0685f17f73 | |||
4b260d5d9f | |||
c8f015c6d7 | |||
604d2155ba | |||
e7727d698f | |||
a3f75f401c | |||
d342f7c429 | |||
bb2b26ca44 | |||
2f9840a51c | |||
09aefdba43 | |||
4c8a408afc | |||
4c08d9a53b | |||
b091cbf361 | |||
a6fcda69ac | |||
9063e4568c | |||
3d37b5d696 | |||
3a8bad1e6f | |||
e822e51752 | |||
f9818f890b | |||
6526118d9f | |||
c15b3b4a09 | |||
e1acb69cf1 | |||
8f757c7b80 | |||
01a47c7d6d | |||
3ee09c6251 | |||
bb54f91dd1 | |||
41a79530e9 | |||
31f5a916f4 | |||
5657a671c1 | |||
ecc254c659 | |||
9cb1c95e49 | |||
e73c46ce03 | |||
952e9c52bc | |||
b879af46b3 | |||
9feb9d6bca | |||
dc0437a5b5 | |||
55331a0678 | |||
f5580f61f9 | |||
30953cf2d7 | |||
c7fa446ee7 | |||
9ecbac365b | |||
80f6fb6329 | |||
1b596a114d | |||
265c00235b | |||
fae37222a7 | |||
d41449b578 | |||
34979c3fe8 | |||
711f0c0c50 | |||
933d05a565 | |||
8a0da1cb07 | |||
1445903a34 | |||
5d9386df0c | |||
6fd1de226b | |||
ac099343da | |||
bce5f3f108 | |||
35e0982e35 | |||
767455e8d8 | |||
6b8dda0d00 | |||
277df44cfb | |||
2dded1e510 | |||
a7b1b1da80 | |||
de69678085 | |||
5f7b81eb95 | |||
f4f70afe31 | |||
116957b339 | |||
1af0033368 | |||
3645c63c08 | |||
04ddfe0a6f | |||
ec3dc4a607 | |||
0b98fbab0a | |||
5b8dc37c31 | |||
f42258327b | |||
7d1ef3f447 | |||
652fe57cdd | |||
20a6243c85 | |||
679edac9c3 | |||
bb59b8c249 | |||
c5c6b2257f | |||
6acf7b06f4 | |||
d0c004c93c | |||
53876d2b62 | |||
2b63b17327 | |||
226a09b38c | |||
527c53a2a0 | |||
19795c1681 | |||
1999fcaa8f | |||
6b5ff8fd74 | |||
821d946a72 | |||
5f7c901727 | |||
7b8ee4ee1e | |||
32cf4afb04 | |||
e0c92befd5 | |||
827e0341ab | |||
8627b65f8d | |||
9c62a907c5 | |||
a119ea96a3 | |||
06d55bf019 | |||
320f38de47 | |||
7adfaceccf | |||
67be4e2bf3 | |||
c3e87ee896 | |||
f2283ec634 | |||
d06e4beb7f | |||
e24863d175 | |||
2de2241690 | |||
977de8c5d4 | |||
fb6438cdd4 | |||
517e8f6fbd | |||
0e758a9e65 | |||
64a915a68d | |||
d233238c64 | |||
71a4fe746e | |||
f28c7835a1 | |||
cecf7f4bf0 | |||
c687cf9db6 | |||
54d2218ac2 | |||
471e6b9e13 | |||
f8dcea3975 | |||
d931af33c4 | |||
a0e3c05428 | |||
b8c13cc426 | |||
38253a9f73 | |||
cbc92b847f | |||
a5f993f269 | |||
31361e464a | |||
bb977c00ca | |||
39f65f9f86 | |||
bda2d6d1ac | |||
1e225ecdaf | |||
cfb85d9a9a | |||
f88c20f335 | |||
c98824bc9e | |||
69a35bb85f | |||
a3bb6c12e5 | |||
586f118279 | |||
31081e5dac | |||
ef363e9d2e | |||
9fa77acb8c | |||
1e30db64d1 | |||
e830b66604 | |||
5f0fab2156 | |||
467465c99c | |||
e935b52e51 | |||
879407c10c | |||
e76be14dbb | |||
7fa15c74b4 | |||
c3950699bf | |||
e6b950e31b | |||
9440bdb1aa | |||
e320b06aaa | |||
b284126d3b | |||
6858cb261f | |||
2d6954186e | |||
d72bf0cd5d | |||
584460deec | |||
e3d5969282 | |||
249468bbea | |||
f0f4c31d96 | |||
27f012ffad | |||
7d54631ebf | |||
513628e4ad | |||
101b215d6b | |||
6af48de0b8 | |||
e5c4fedd55 | |||
2ce23072d3 | |||
97f4eb6b75 | |||
75cbf3d730 | |||
bf9fdf448d | |||
63c627ec18 | |||
dadbd793be | |||
75b6e917ad | |||
ab53c0e943 | |||
c2fe6a18ad | |||
b7119c55a6 | |||
d0f2c6be6d | |||
3a535b6722 | |||
f9a77aec3f | |||
bee6d2b240 | |||
9a6a189e36 | |||
505eabb78c | |||
b0ba325f0e | |||
6fbd21001b | |||
626e4965b1 | |||
a15042b7e5 | |||
e56f963574 | |||
65a8f9100c | |||
6954d23444 | |||
6c624e1c26 | |||
cc839029b9 | |||
25f8eaf1ac | |||
8fdd226b8b | |||
6c5595fa9c | |||
e6558f838e | |||
57037a45b8 | |||
c844611052 | |||
b60e02956d | |||
4fe66ce0a9 | |||
4b5a503cee | |||
817995d97f | |||
0e7221c361 | |||
938fb8e6c8 | |||
fd8c49ff0a | |||
cd84317346 | |||
4f55e16fe9 | |||
c30ef668de | |||
62e0c42803 | |||
70aee2d95e | |||
63c7591698 | |||
930361b988 | |||
baadb75a5e | |||
f28f5dc0b6 | |||
41fdc4ac2e | |||
177ec27cca | |||
37652ca2cf | |||
6c22759d29 | |||
25b6a40ad4 | |||
fbea59b326 | |||
38e4906f72 | |||
029d69919b | |||
5e395fb676 | |||
ac448bd42b | |||
f55737ec06 | |||
80de15face | |||
32565e096d | |||
1d8e4bdd6d | |||
1677a068ce | |||
a02b8441b1 | |||
dfe1c106f2 | |||
e49bbe2ed8 | |||
6ee5a1437c | |||
93a3383e60 | |||
c9a2a561f8 | |||
ac0b2fdc6f | |||
46b9984414 | |||
f9743e2174 | |||
a3c55c2692 | |||
692eb4d957 | |||
826751429b | |||
5621d3c0c7 | |||
b5f46c9171 | |||
166b8c042c | |||
d34ece6f1a | |||
679844f791 | |||
9316256e10 | |||
90d7737fc1 | |||
567ca15610 | |||
558b323485 | |||
1a05da8296 | |||
5df59f75cd | |||
029673d0ee | |||
3a57f843d5 | |||
182a267f69 | |||
3de40434fa | |||
bc8328d7c2 | |||
12c1a06e60 | |||
b11405570a | |||
3b85e4b2b9 | |||
c5abf5ddbb | |||
2a3d4b62a7 | |||
8ff81bcc37 | |||
7159d3bc35 | |||
941d202938 | |||
5ea0cf8bab | |||
df9a5f867f | |||
06e4778072 | |||
92388892b3 | |||
5d124ac00a | |||
a57c3ae105 | |||
55354f5c38 | |||
379bb0a77d | |||
39357fc242 | |||
799de4f0f4 | |||
c34b5c1cf0 | |||
46361c3e28 | |||
f9d33b2efc | |||
2185904fcb | |||
eb952819c2 | |||
d7d8c92a9a | |||
88a7790d44 | |||
806dabe2d7 | |||
740e7ddd69 | |||
bee97ab6a7 | |||
59fc17c355 | |||
5f25ca0c3a | |||
41b4a079c7 | |||
e4235376d8 | |||
043a201f90 | |||
d1a588a94f | |||
01b6d9bfe2 | |||
9711d95996 | |||
b87db00fdb | |||
6190b65056 | |||
10fe91d704 | |||
36bb05b10e | |||
a7b7213017 | |||
031154a400 | |||
463b50e746 | |||
1749a85e96 | |||
1af9e92e91 | |||
12d0c98fb5 | |||
817c6986a0 | |||
7c68aaea4c | |||
6fea46e0cf | |||
59fa74fed1 | |||
581335fbea | |||
9b5d6cc008 | |||
d0f98ec1ba | |||
a977fcf3d0 | |||
664f6ef420 | |||
06a31992e3 | |||
4e2092d593 | |||
9755f308e5 | |||
09610daea1 | |||
13b7fa4eba | |||
909a46087f | |||
c10c8649f5 | |||
82dce6758a | |||
024652bfb4 | |||
789608b637 | |||
d05b750b8d | |||
704cae1de3 | |||
23b074481a | |||
5dc8fa6690 | |||
a9ba98686f | |||
59382bace2 | |||
2edf822bc6 | |||
355621b0ab | |||
a307e13a63 | |||
f807207b65 | |||
30b54aae34 | |||
79e682bcd0 | |||
a05ae8654c | |||
0db172edbf | |||
7b0930f798 | |||
0919b37c34 | |||
faf55c4627 | |||
f351c5d304 | |||
63bca17ab6 | |||
c2abe43ee7 | |||
1de2fd7122 | |||
e377e82cfd | |||
fa8174a200 | |||
d22448731c | |||
ef95133b1c | |||
c068c2122d | |||
d8c47b0abd | |||
66eb4bc34c | |||
bce812ecbc | |||
02220ed6c7 | |||
8d08851f28 | |||
af135c0b0b | |||
42c972735e | |||
110c79d10e | |||
b9d867cb86 | |||
ea3b961e43 | |||
bc510378b3 | |||
0a47d135ac | |||
ec8ed1dbb0 | |||
203e5335ab | |||
f1d8428650 | |||
8d29d22e99 | |||
9c6e527d4b | |||
077606c057 | |||
a615f93060 | |||
c562657f1e | |||
7b3922f8e9 | |||
c14382181f | |||
b2183dfda7 | |||
bb92054c86 | |||
4e4a6eb5d7 | |||
692acbd986 | |||
901901825c |
14
.gitignore
vendored
14
.gitignore
vendored
@ -43,6 +43,10 @@ POTFILES
|
||||
po/*.pot
|
||||
libmutter.pc
|
||||
mutter
|
||||
mutter-restart-helper
|
||||
mutter-test-client
|
||||
mutter-test-runner
|
||||
mutter-all.test
|
||||
org.gnome.mutter.gschema.valid
|
||||
org.gnome.mutter.gschema.xml
|
||||
org.gnome.mutter.wayland.gschema.valid
|
||||
@ -51,16 +55,6 @@ testasyncgetprop
|
||||
testboxes
|
||||
testgradient
|
||||
m4/*
|
||||
mutter-grayscale
|
||||
mutter-mag
|
||||
mutter-message
|
||||
mutter-window-demo
|
||||
focus-window
|
||||
test-attached
|
||||
test-focus
|
||||
test-gravity
|
||||
test-resizing
|
||||
test-size-hints
|
||||
INSTALL
|
||||
mkinstalldirs
|
||||
src/mutter-enum-types.[ch]
|
||||
|
80
NEWS
80
NEWS
@ -1,3 +1,83 @@
|
||||
3.13.92
|
||||
=======
|
||||
* Rewrite background code [Owen; #735637, #736568]
|
||||
* Fix size in nested mode [Owen; #736279]
|
||||
* Fix destroy animation of background windows [Florian; #735927]
|
||||
* Wire keymap changes up to the wayland frontend [Rui; #736433]
|
||||
* Add a test framework and stacking tests [Owen; #736505]
|
||||
* Simplify handling of the merged X and wayland stack [Owen; #736559]
|
||||
* Fix cursor size on HiDPI [Adel; #729337]
|
||||
* Misc. bug fixes [Owen; #735632, #736589, #736694]
|
||||
|
||||
Contributors:
|
||||
Adel Gadllah, Rui Matos, Florian Müllner, Jasper St. Pierre, Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Andika Triwidada [id], Piotr Drąg [pl], Changwoo Ryu [ko],
|
||||
Kjartan Maraas [nb], Ville-Pekka Vainio [fi], Yuri Myasoedov [ru],
|
||||
Aurimas Černius [lt], Balázs Úr [hu], Sweta Kothari [gu], A S Alam [pa],
|
||||
Sandeep Sheshrao Shedmake [mr], Shantha kumar [ta], Gil Forcada [ca],
|
||||
Carles Ferrando [ca@valencia], Mattias Eriksson [sv]
|
||||
|
||||
3.13.91
|
||||
=======
|
||||
* Misc. bug fixes [Carlos; #735452]
|
||||
|
||||
Contributors:
|
||||
Adel Gadllah, Carlos Garnacho, Rui Matos, Jasper St. Pierre,
|
||||
Rico Tzschichholz
|
||||
|
||||
Translations:
|
||||
Chao-Hsiung Liao po/zh_HK, zh_TW.po, Enrico Nicoletto [pt_BR],
|
||||
Kjartan Maraas [nb], Fran Diéguez [gl], Yosef Or Boczko [he],
|
||||
Maria Mavridou [el], Claude Paroz [fr]
|
||||
|
||||
3.13.90
|
||||
=======
|
||||
* Only call XSync() once per frame [Rui; #728464]
|
||||
* Update capabilities on device list changes [Carlos; #733563]
|
||||
* Make use of GLSL optional [Adel; #733623]
|
||||
* Handle gestures and touch events on wayland [Carlos; #733631]
|
||||
* Add support for unminimize compositor effects [Cosimo; #733789]
|
||||
* Always set the frame background to None [Giovanni; #734054]
|
||||
* Add backend methods to handle keymaps [Rui; #734301]
|
||||
* Actually mark revalidated MetaTextureTower levels as valid [Owen; #734400]
|
||||
* Rely on explicit -backward switcher keybindings instead of <shift>-magic
|
||||
[Christophe; #732295, #732385]
|
||||
* Misc. bug fixes and cleanups [Rui, Adel, Christophe; #727178, #734852,
|
||||
#734960]
|
||||
|
||||
Contributors:
|
||||
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Piotr Drąg,
|
||||
Christophe Fergeau, Adel Gadllah, Carlos Garnacho, Rui Matos,
|
||||
Florian Müllner, Jasper St. Pierre, Rico Tzschichholz, Olav Vitters,
|
||||
Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Kjartan Maraas [nb], Inaki Larranaga Murgoitio [eu], Lasse Liehu [fi],
|
||||
ngoswami [as], Daniel Mustieles [es]
|
||||
|
||||
3.13.4
|
||||
======
|
||||
* Fix move/resize operations for wayland clients [Marek; #731237]
|
||||
* Add ::first-frame signal to MetaWindowActor [Owen; #732343]
|
||||
* Handle keysyms without the XF86 prefix [Owen; #727993]
|
||||
* Add touch gesture support [Carlos]
|
||||
* Fix a deadlock when exiting [Owen; #733068]
|
||||
* Add framework for restarting the compositor with nice visuals
|
||||
[Owen; #733026]
|
||||
* Toggle seat capabilities on VT switch [Carlos; #733563]
|
||||
* Misc bug fixes [Florian, Owen; #732695, #732350]
|
||||
|
||||
Contributors:
|
||||
Tom Beckmann, Giovanni Campagna, Marek Chalupa, Adel Gadllah,
|
||||
Carlos Garnacho, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz,
|
||||
Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Yuri Myasoedov [ru], Fran Diéguez [gl], Aurimas Černius [lt], MarMav [el],
|
||||
Enrico Nicoletto [pt_BR]
|
||||
|
||||
3.13.3
|
||||
======
|
||||
* Improve behavior of window buttons with compositor menus [Florian; #731058]
|
||||
|
59
configure.ac
59
configure.ac
@ -2,7 +2,7 @@ AC_PREREQ(2.62)
|
||||
|
||||
m4_define([mutter_major_version], [3])
|
||||
m4_define([mutter_minor_version], [13])
|
||||
m4_define([mutter_micro_version], [3])
|
||||
m4_define([mutter_micro_version], [92])
|
||||
|
||||
m4_define([mutter_version],
|
||||
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
||||
@ -72,20 +72,28 @@ CLUTTER_PACKAGE=clutter-1.0
|
||||
|
||||
MUTTER_PC_MODULES="
|
||||
gtk+-3.0 >= 3.9.11
|
||||
gio-2.0 >= 2.25.10
|
||||
gio-unix-2.0 >= 2.25.10
|
||||
pango >= 1.2.0
|
||||
cairo >= 1.10.0
|
||||
gsettings-desktop-schemas >= 3.7.3
|
||||
xcomposite >= 0.2 xfixes xext xdamage xi >= 1.6.0
|
||||
xcursor
|
||||
$CLUTTER_PACKAGE >= 1.17.5
|
||||
clutter-wayland-1.0
|
||||
clutter-wayland-compositor-1.0
|
||||
$CLUTTER_PACKAGE >= 1.19.5
|
||||
clutter-egl-1.0
|
||||
cogl-1.0 >= 1.17.1
|
||||
wayland-server >= 1.4.93
|
||||
gbm
|
||||
upower-glib >= 0.99.0
|
||||
gnome-desktop-3.0
|
||||
xcomposite >= 0.2
|
||||
xcursor
|
||||
xdamage
|
||||
xext
|
||||
xfixes
|
||||
xi >= 1.6.0
|
||||
xkbfile
|
||||
xkeyboard-config
|
||||
xkbcommon >= 0.4.3
|
||||
xkbcommon-x11
|
||||
x11-xcb
|
||||
xcb-randr
|
||||
"
|
||||
|
||||
GLIB_GSETTINGS
|
||||
@ -119,6 +127,12 @@ AC_ARG_WITH([xwayland-path],
|
||||
[XWAYLAND_PATH="$withval"],
|
||||
[XWAYLAND_PATH="$bindir/Xwayland"])
|
||||
|
||||
AC_ARG_ENABLE(installed_tests,
|
||||
AS_HELP_STRING([--enable-installed-tests],
|
||||
[Install test programs (default: no)]),,
|
||||
[enable_installed_tests=no])
|
||||
AM_CONDITIONAL(BUILDOPT_INSTALL_TESTS, test x$enable_installed_tests = xyes)
|
||||
|
||||
## here we get the flags we'll actually use
|
||||
|
||||
# Unconditionally use this dir to avoid a circular dep with gnomecc
|
||||
@ -184,20 +198,27 @@ if test x$found_introspection != xno; then
|
||||
AC_SUBST(META_GIR)
|
||||
fi
|
||||
|
||||
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
|
||||
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
||||
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [libdrm libsystemd], [have_native_backend=yes], [have_native_backend=no])
|
||||
PKG_CHECK_MODULES(MUTTER_NATIVE_BACKEND, [libdrm libsystemd libinput], [have_native_backend=yes], [have_native_backend=no])
|
||||
if test $have_native_backend = yes; then
|
||||
AC_DEFINE([HAVE_NATIVE_BACKEND],[1],[Define if you want to enable the native (KMS) backend based on systemd])
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_NATIVE_BACKEND],[test $have_native_backend = yes])
|
||||
|
||||
PKG_CHECK_MODULES(MUTTER_WAYLAND, [clutter-wayland-1.0 clutter-wayland-compositor-1.0 wayland-server >= 1.5.90], [have_wayland=yes], [have_wayland=no])
|
||||
if test $have_wayland = yes; then
|
||||
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
|
||||
AS_IF([test $WAYLAND_SCANNER = "no"],
|
||||
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
|
||||
AC_DEFINE([HAVE_WAYLAND],[1],[Define if you want to enable Wayland support])
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_WAYLAND],[test $have_wayland = yes])
|
||||
|
||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||
AC_DEFINE([HAVE_XI23],[1],[Define if you have support for XInput 2.3 or greater]))
|
||||
|
||||
@ -234,16 +255,8 @@ if test x$have_xinerama = xno; then
|
||||
AC_MSG_ERROR([Xinerama extension was not found])
|
||||
fi
|
||||
|
||||
found_xkb=no
|
||||
AC_CHECK_LIB(X11, XkbQueryExtension,
|
||||
[AC_CHECK_HEADER(X11/XKBlib.h,
|
||||
found_xkb=yes)],
|
||||
, $ALL_X_LIBS)
|
||||
|
||||
if test "x$found_xkb" = "xyes"; then
|
||||
AC_DEFINE(HAVE_XKB, , [Have keyboard extension library])
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED([XKB_BASE], ["`$PKG_CONFIG --variable xkb_base xkeyboard-config`"],
|
||||
[XKB base dir])
|
||||
|
||||
RANDR_LIBS=
|
||||
found_randr=no
|
||||
|
@ -45,26 +45,68 @@
|
||||
_description="Move window one monitor down" />
|
||||
|
||||
<KeyListEntry name="switch-applications"
|
||||
reverse-entry="switch-applications-backward"
|
||||
_description="Switch applications"/>
|
||||
|
||||
<KeyListEntry name="switch-applications-backward"
|
||||
reverse-entry="switch-applications"
|
||||
hidden="true"
|
||||
_description="Switch to previous application"/>
|
||||
|
||||
<KeyListEntry name="switch-windows"
|
||||
reverse-entry="switch-windows-backward"
|
||||
_description="Switch windows"/>
|
||||
|
||||
<KeyListEntry name="switch-windows-backward"
|
||||
reverse-entry="switch-windows"
|
||||
hidden="true"
|
||||
_description="Switch to previous window"/>
|
||||
|
||||
<KeyListEntry name="switch-group"
|
||||
reverse-entry="switch-group-backward"
|
||||
_description="Switch windows of an application"/>
|
||||
|
||||
<KeyListEntry name="switch-group-backward"
|
||||
reverse-entry="switch-group"
|
||||
hidden="true"
|
||||
_description="Switch to previous window of an application"/>
|
||||
|
||||
<KeyListEntry name="switch-panels"
|
||||
reverse-entry="switch-panels-backward"
|
||||
_description="Switch system controls"/>
|
||||
|
||||
<KeyListEntry name="switch-panels-backward"
|
||||
reverse-entry="switch-panels"
|
||||
hidden="true"
|
||||
_description="Switch to previous system control"/>
|
||||
|
||||
<KeyListEntry name="cycle-windows"
|
||||
reverse-entry="cycle-windows-backward"
|
||||
_description="Switch windows directly"/>
|
||||
|
||||
<KeyListEntry name="cycle-windows-backward"
|
||||
reverse-entry="cycle-windows"
|
||||
hidden="true"
|
||||
_description="Switch directly to previous window"/>
|
||||
|
||||
<KeyListEntry name="cycle-group"
|
||||
reverse-entry="cycle-group-backward"
|
||||
_description="Switch windows of an app directly"/>
|
||||
|
||||
<KeyListEntry name="cycle-group-backward"
|
||||
reverse-entry="cycle-group"
|
||||
hidden="true"
|
||||
_description="Switch directly to previous window of an app"/>
|
||||
|
||||
<KeyListEntry name="cycle-panels"
|
||||
reverse-entry="cycle-panels-backward"
|
||||
_description="Switch system controls directly"/>
|
||||
|
||||
<KeyListEntry name="cycle-panels-backward"
|
||||
reverse-entry="cycle-panels"
|
||||
hidden="true"
|
||||
_description="Switch directly to previous system control"/>
|
||||
|
||||
<KeyListEntry name="show-desktop"
|
||||
_description="Hide all normal windows"/>
|
||||
|
||||
|
@ -111,6 +111,13 @@ IGNORE_HFILES= \
|
||||
xprops.h \
|
||||
$(NULL)
|
||||
|
||||
if !HAVE_WAYLAND
|
||||
IGNORE_HFILES += \
|
||||
meta-surface-actor-wayland.h \
|
||||
wayland \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
MKDB_OPTIONS+=--ignore-files="$(IGNORE_HFILES)"
|
||||
|
||||
# Images to copy into HTML directory.
|
||||
|
@ -300,6 +300,7 @@ MetaPluginVersion
|
||||
META_PLUGIN_DECLARE
|
||||
meta_plugin_switch_workspace_completed
|
||||
meta_plugin_minimize_completed
|
||||
meta_plugin_unminimize_completed
|
||||
meta_plugin_maximize_completed
|
||||
meta_plugin_unmaximize_completed
|
||||
meta_plugin_map_completed
|
||||
|
@ -23,7 +23,8 @@ environment.</description>
|
||||
<download-page rdf:resource="http://download.gnome.org/sources/mutter/" />
|
||||
<bug-database rdf:resource="http://bugzilla.gnome.org/browse.cgi?product=mutter" />
|
||||
|
||||
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />
|
||||
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
|
||||
<programming-language>C</programming-language>
|
||||
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
|
1275
po/ca@valencia.po
1275
po/ca@valencia.po
File diff suppressed because it is too large
Load Diff
1308
po/pt_BR.po
1308
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
1267
po/zh_HK.po
1267
po/zh_HK.po
File diff suppressed because it is too large
Load Diff
1295
po/zh_TW.po
1295
po/zh_TW.po
File diff suppressed because it is too large
Load Diff
50
src/Makefile-tests.am
Normal file
50
src/Makefile-tests.am
Normal file
@ -0,0 +1,50 @@
|
||||
# A framework for running scripted tests
|
||||
|
||||
if HAVE_WAYLAND
|
||||
|
||||
if BUILDOPT_INSTALL_TESTS
|
||||
stackingdir = $(pkgdatadir)/tests/stacking
|
||||
dist_stacking_DATA = \
|
||||
tests/stacking/basic-x11.metatest \
|
||||
tests/stacking/basic-wayland.metatest \
|
||||
tests/stacking/mixed-windows.metatest \
|
||||
tests/stacking/override-redirect.metatest
|
||||
|
||||
mutter-all.test: tests/mutter-all.test.in
|
||||
$(AM_V_GEN) sed -e "s|@libexecdir[@]|$(libexecdir)|g" $< > $@.tmp && mv $@.tmp $@
|
||||
|
||||
installedtestsdir = $(datadir)/installed-tests/mutter
|
||||
installedtests_DATA = mutter-all.test
|
||||
|
||||
installedtestsbindir = $(libexecdir)/installed-tests/mutter
|
||||
installedtestsbin_PROGRAMS = mutter-test-client mutter-test-runner
|
||||
else
|
||||
noinst_PROGRAMS += mutter-test-client mutter-test-runner
|
||||
endif
|
||||
|
||||
EXTRA_DIST += tests/mutter-all.test.in
|
||||
|
||||
mutter_test_client_SOURCES = tests/test-client.c
|
||||
mutter_test_client_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
|
||||
mutter_test_runner_SOURCES = tests/test-runner.c
|
||||
mutter_test_runner_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
|
||||
.PHONY: run-tests
|
||||
|
||||
run-tests: mutter-test-client mutter-test-runner
|
||||
./mutter-test-runner $(dist_stacking_DATA)
|
||||
|
||||
endif
|
||||
|
||||
# Some random test programs for bits of the code
|
||||
|
||||
testboxes_SOURCES = core/testboxes.c
|
||||
testgradient_SOURCES = ui/testgradient.c
|
||||
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
|
||||
|
||||
noinst_PROGRAMS+=testboxes testgradient testasyncgetprop
|
||||
|
||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
|
@ -5,11 +5,15 @@ lib_LTLIBRARIES = libmutter.la
|
||||
|
||||
SUBDIRS=compositor/plugins
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DCLUTTER_ENABLE_COMPOSITOR_API \
|
||||
-DCLUTTER_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
|
||||
-DCLUTTER_DISABLE_DEPRECATION_WARNINGS \
|
||||
-DCOGL_DISABLE_DEPRECATION_WARNINGS \
|
||||
$(MUTTER_CFLAGS) \
|
||||
$(MUTTER_NATIVE_BACKEND_CFLAGS) \
|
||||
-I$(builddir) \
|
||||
@ -33,13 +37,16 @@ mutter_built_sources = \
|
||||
$(dbus_idle_built_sources) \
|
||||
$(dbus_display_config_built_sources) \
|
||||
$(dbus_login1_built_sources) \
|
||||
meta/meta-version.h \
|
||||
mutter-enum-types.h \
|
||||
mutter-enum-types.c \
|
||||
mutter-enum-types.c
|
||||
|
||||
if HAVE_WAYLAND
|
||||
mutter_built_sources += \
|
||||
gtk-shell-protocol.c \
|
||||
gtk-shell-server-protocol.h \
|
||||
xdg-shell-protocol.c \
|
||||
xdg-shell-server-protocol.h
|
||||
endif
|
||||
|
||||
wayland_protocols = \
|
||||
wayland/protocol/gtk-shell.xml \
|
||||
@ -47,7 +54,7 @@ wayland_protocols = \
|
||||
|
||||
libmutter_la_SOURCES = \
|
||||
backends/meta-backend.c \
|
||||
backends/meta-backend.h \
|
||||
meta/meta-backend.h \
|
||||
backends/meta-backend-private.h \
|
||||
backends/meta-cursor.c \
|
||||
backends/meta-cursor.h \
|
||||
@ -67,6 +74,8 @@ libmutter_la_SOURCES = \
|
||||
backends/meta-monitor-manager.h \
|
||||
backends/meta-monitor-manager-dummy.c \
|
||||
backends/meta-monitor-manager-dummy.h \
|
||||
backends/meta-stage.h \
|
||||
backends/meta-stage.c \
|
||||
backends/edid-parse.c \
|
||||
backends/edid.h \
|
||||
backends/x11/meta-backend-x11.c \
|
||||
@ -93,8 +102,10 @@ libmutter_la_SOURCES = \
|
||||
compositor/compositor.c \
|
||||
compositor/compositor-private.h \
|
||||
compositor/meta-background.c \
|
||||
compositor/meta-background-private.h \
|
||||
compositor/meta-background-actor.c \
|
||||
compositor/meta-background-actor-private.h \
|
||||
compositor/meta-background-image.c \
|
||||
compositor/meta-background-group.c \
|
||||
compositor/meta-cullable.c \
|
||||
compositor/meta-cullable.h \
|
||||
@ -111,10 +122,6 @@ libmutter_la_SOURCES = \
|
||||
compositor/meta-surface-actor.h \
|
||||
compositor/meta-surface-actor-x11.c \
|
||||
compositor/meta-surface-actor-x11.h \
|
||||
compositor/meta-surface-actor-wayland.c \
|
||||
compositor/meta-surface-actor-wayland.h \
|
||||
compositor/meta-stage.h \
|
||||
compositor/meta-stage.c \
|
||||
compositor/meta-texture-rectangle.c \
|
||||
compositor/meta-texture-rectangle.h \
|
||||
compositor/meta-texture-tower.c \
|
||||
@ -130,6 +137,7 @@ libmutter_la_SOURCES = \
|
||||
meta/compositor.h \
|
||||
meta/meta-background.h \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-image.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-plugin.h \
|
||||
meta/meta-shadow-factory.h \
|
||||
@ -152,6 +160,8 @@ libmutter_la_SOURCES = \
|
||||
core/frame.h \
|
||||
ui/gradient.c \
|
||||
meta/gradient.h \
|
||||
core/meta-gesture-tracker.c \
|
||||
core/meta-gesture-tracker-private.h \
|
||||
core/keybindings.c \
|
||||
core/keybindings-private.h \
|
||||
core/main.c \
|
||||
@ -163,6 +173,7 @@ libmutter_la_SOURCES = \
|
||||
core/screen-private.h \
|
||||
meta/screen.h \
|
||||
meta/types.h \
|
||||
core/restart.c \
|
||||
core/stack.c \
|
||||
core/stack.h \
|
||||
core/stack-tracker.c \
|
||||
@ -207,7 +218,12 @@ libmutter_la_SOURCES = \
|
||||
x11/window-x11-private.h \
|
||||
x11/xprops.c \
|
||||
x11/xprops.h \
|
||||
x11/mutter-Xatomtype.h \
|
||||
x11/mutter-Xatomtype.h
|
||||
|
||||
if HAVE_WAYLAND
|
||||
libmutter_la_SOURCES += \
|
||||
compositor/meta-surface-actor-wayland.c \
|
||||
compositor/meta-surface-actor-wayland.h \
|
||||
wayland/meta-wayland.c \
|
||||
wayland/meta-wayland.h \
|
||||
wayland/meta-wayland-private.h \
|
||||
@ -232,6 +248,7 @@ libmutter_la_SOURCES = \
|
||||
wayland/meta-wayland-outputs.h \
|
||||
wayland/window-wayland.c \
|
||||
wayland/window-wayland.h
|
||||
endif
|
||||
|
||||
if HAVE_NATIVE_BACKEND
|
||||
libmutter_la_SOURCES += \
|
||||
@ -269,9 +286,11 @@ libmutterinclude_headers = \
|
||||
meta/group.h \
|
||||
meta/keybindings.h \
|
||||
meta/main.h \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-backend.h \
|
||||
meta/meta-background.h \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-image.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-cursor-tracker.h \
|
||||
meta/meta-idle-monitor.h \
|
||||
meta/meta-plugin.h \
|
||||
@ -308,10 +327,17 @@ nodist_libmutterinclude_HEADERS = \
|
||||
$(libmutterinclude_built_headers)
|
||||
|
||||
bin_PROGRAMS=mutter
|
||||
noinst_PROGRAMS=
|
||||
|
||||
mutter_SOURCES = core/mutter.c
|
||||
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
|
||||
libexec_PROGRAMS = mutter-restart-helper
|
||||
mutter_restart_helper_SOURCES = core/restart-helper.c
|
||||
mutter_restart_helper_LDADD = $(MUTTER_LIBS)
|
||||
|
||||
include Makefile-tests.am
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
include $(INTROSPECTION_MAKEFILE)
|
||||
|
||||
@ -345,28 +371,20 @@ Meta-$(api_version).gir: libmutter.la
|
||||
|
||||
endif
|
||||
|
||||
testboxes_SOURCES = core/testboxes.c
|
||||
testgradient_SOURCES = ui/testgradient.c
|
||||
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
|
||||
|
||||
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
|
||||
|
||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
|
||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||
|
||||
CLEANFILES = \
|
||||
$(mutter_built_sources) \
|
||||
$(libmutterinclude_built_headers) \
|
||||
$(typelib_DATA) \
|
||||
$(gir_DATA)
|
||||
|
||||
DISTCLEANFILES = \
|
||||
$(libmutterinclude_built_headers)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libmutter.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
EXTRA_DIST += \
|
||||
$(wayland_protocols) \
|
||||
libmutter.pc.in \
|
||||
mutter-enum-types.h.in \
|
||||
@ -375,7 +393,10 @@ EXTRA_DIST = \
|
||||
org.gnome.Mutter.DisplayConfig.xml \
|
||||
org.gnome.Mutter.IdleMonitor.xml
|
||||
|
||||
BUILT_SOURCES = $(mutter_built_sources)
|
||||
BUILT_SOURCES = \
|
||||
$(mutter_built_sources) \
|
||||
$(libmutterinclude_built_headers)
|
||||
|
||||
MUTTER_STAMP_FILES = stamp-mutter-enum-types.h
|
||||
CLEANFILES += $(MUTTER_STAMP_FILES)
|
||||
|
||||
|
@ -189,7 +189,5 @@ struct MonitorInfo
|
||||
};
|
||||
|
||||
MonitorInfo *decode_edid (const uchar *data);
|
||||
char *make_display_name (const MonitorInfo *info);
|
||||
char *make_display_size_string (int width_mm, int height_mm);
|
||||
|
||||
#endif
|
||||
|
@ -28,7 +28,15 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "meta-backend.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include <meta/meta-backend.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "meta-cursor-renderer.h"
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#define DEFAULT_XKB_RULES_FILE "evdev"
|
||||
#define DEFAULT_XKB_MODEL "pc105+inet"
|
||||
|
||||
#define META_TYPE_BACKEND (meta_backend_get_type ())
|
||||
#define META_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKEND, MetaBackend))
|
||||
@ -66,6 +74,37 @@ struct _MetaBackendClass
|
||||
void (* warp_pointer) (MetaBackend *backend,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
void (* set_keymap) (MetaBackend *backend,
|
||||
const char *layouts,
|
||||
const char *variants,
|
||||
const char *options);
|
||||
|
||||
struct xkb_keymap * (* get_keymap) (MetaBackend *backend);
|
||||
|
||||
void (* lock_layout_group) (MetaBackend *backend,
|
||||
guint idx);
|
||||
|
||||
void (* update_screen_size) (MetaBackend *backend, int width, int height);
|
||||
void (* select_stage_events) (MetaBackend *backend);
|
||||
};
|
||||
|
||||
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
|
||||
int device_id);
|
||||
MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend);
|
||||
MetaCursorRenderer * meta_backend_get_cursor_renderer (MetaBackend *backend);
|
||||
|
||||
gboolean meta_backend_grab_device (MetaBackend *backend,
|
||||
int device_id,
|
||||
uint32_t timestamp);
|
||||
gboolean meta_backend_ungrab_device (MetaBackend *backend,
|
||||
int device_id,
|
||||
uint32_t timestamp);
|
||||
|
||||
void meta_backend_warp_pointer (MetaBackend *backend,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
|
||||
|
||||
#endif /* META_BACKEND_PRIVATE_H */
|
||||
|
@ -24,12 +24,11 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-backend.h"
|
||||
#include <meta/meta-backend.h>
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "meta-stage.h"
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
@ -37,6 +36,13 @@
|
||||
|
||||
static MetaBackend *_backend;
|
||||
|
||||
/**
|
||||
* meta_get_backend:
|
||||
*
|
||||
* Accessor for the singleton MetaBackend.
|
||||
*
|
||||
* Returns: (transfer none): The only #MetaBackend there is.
|
||||
*/
|
||||
MetaBackend *
|
||||
meta_get_backend (void)
|
||||
{
|
||||
@ -47,6 +53,8 @@ struct _MetaBackendPrivate
|
||||
{
|
||||
MetaMonitorManager *monitor_manager;
|
||||
MetaCursorRenderer *cursor_renderer;
|
||||
|
||||
ClutterActor *stage;
|
||||
};
|
||||
typedef struct _MetaBackendPrivate MetaBackendPrivate;
|
||||
|
||||
@ -70,13 +78,121 @@ meta_backend_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (meta_backend_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_sync_screen_size (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
int width, height;
|
||||
|
||||
meta_monitor_manager_get_screen_size (priv->monitor_manager, &width, &height);
|
||||
|
||||
META_BACKEND_GET_CLASS (backend)->update_screen_size (backend, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
on_monitors_changed (MetaMonitorManager *monitors,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackend *backend = META_BACKEND (user_data);
|
||||
meta_backend_sync_screen_size (backend);
|
||||
}
|
||||
|
||||
static MetaIdleMonitor *
|
||||
meta_backend_create_idle_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
return META_BACKEND_GET_CLASS (backend)->create_idle_monitor (backend, device_id);
|
||||
}
|
||||
|
||||
static void
|
||||
create_device_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
g_assert (backend->device_monitors[device_id] == NULL);
|
||||
|
||||
backend->device_monitors[device_id] = meta_backend_create_idle_monitor (backend, device_id);
|
||||
backend->device_id_max = MAX (backend->device_id_max, device_id);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_device_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
g_clear_object (&backend->device_monitors[device_id]);
|
||||
|
||||
if (device_id == backend->device_id_max)
|
||||
{
|
||||
/* Reset the max device ID */
|
||||
int i, new_max = 0;
|
||||
for (i = 0; i < backend->device_id_max; i++)
|
||||
if (backend->device_monitors[i] != NULL)
|
||||
new_max = i;
|
||||
backend->device_id_max = new_max;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_added (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackend *backend = META_BACKEND (user_data);
|
||||
int device_id = clutter_input_device_get_device_id (device);
|
||||
|
||||
create_device_monitor (backend, device_id);
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_removed (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackend *backend = META_BACKEND (user_data);
|
||||
int device_id = clutter_input_device_get_device_id (device);
|
||||
|
||||
destroy_device_monitor (backend, device_id);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_real_post_init (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
priv->stage = meta_stage_new ();
|
||||
clutter_actor_realize (priv->stage);
|
||||
META_BACKEND_GET_CLASS (backend)->select_stage_events (backend);
|
||||
|
||||
priv->monitor_manager = META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend);
|
||||
|
||||
g_signal_connect (priv->monitor_manager, "monitors-changed",
|
||||
G_CALLBACK (on_monitors_changed), backend);
|
||||
meta_backend_sync_screen_size (backend);
|
||||
|
||||
priv->cursor_renderer = META_BACKEND_GET_CLASS (backend)->create_cursor_renderer (backend);
|
||||
|
||||
{
|
||||
ClutterDeviceManager *manager;
|
||||
GSList *devices, *l;
|
||||
|
||||
/* Create the core device monitor. */
|
||||
create_device_monitor (backend, 0);
|
||||
|
||||
manager = clutter_device_manager_get_default ();
|
||||
g_signal_connect_object (manager, "device-added",
|
||||
G_CALLBACK (on_device_added), backend, 0);
|
||||
g_signal_connect_object (manager, "device-removed",
|
||||
G_CALLBACK (on_device_removed), backend, 0);
|
||||
|
||||
devices = clutter_device_manager_list_devices (manager);
|
||||
|
||||
for (l = devices; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterInputDevice *device = l->data;
|
||||
on_device_added (manager, device, backend);
|
||||
}
|
||||
|
||||
g_slist_free (devices);
|
||||
}
|
||||
}
|
||||
|
||||
static MetaCursorRenderer *
|
||||
@ -103,6 +219,21 @@ meta_backend_real_ungrab_device (MetaBackend *backend,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_real_update_screen_size (MetaBackend *backend,
|
||||
int width, int height)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
clutter_actor_set_size (priv->stage, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_real_select_stage_events (MetaBackend *backend)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_class_init (MetaBackendClass *klass)
|
||||
{
|
||||
@ -114,6 +245,21 @@ meta_backend_class_init (MetaBackendClass *klass)
|
||||
klass->create_cursor_renderer = meta_backend_real_create_cursor_renderer;
|
||||
klass->grab_device = meta_backend_real_grab_device;
|
||||
klass->ungrab_device = meta_backend_real_ungrab_device;
|
||||
klass->update_screen_size = meta_backend_real_update_screen_size;
|
||||
klass->select_stage_events = meta_backend_real_select_stage_events;
|
||||
|
||||
g_signal_new ("keymap-changed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
g_signal_new ("keymap-layout-group-changed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -122,44 +268,27 @@ meta_backend_init (MetaBackend *backend)
|
||||
_backend = backend;
|
||||
}
|
||||
|
||||
/* FIXME -- destroy device monitors at some point */
|
||||
G_GNUC_UNUSED static void
|
||||
destroy_device_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
g_clear_object (&backend->device_monitors[device_id]);
|
||||
if (device_id == backend->device_id_max)
|
||||
backend->device_id_max--;
|
||||
}
|
||||
|
||||
static MetaIdleMonitor *
|
||||
meta_backend_create_idle_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
return META_BACKEND_GET_CLASS (backend)->create_idle_monitor (backend, device_id);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_post_init (MetaBackend *backend)
|
||||
{
|
||||
META_BACKEND_GET_CLASS (backend)->post_init (backend);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_get_idle_monitor: (skip)
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_backend_get_idle_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
g_return_val_if_fail (device_id >= 0 && device_id < 256, NULL);
|
||||
|
||||
if (!backend->device_monitors[device_id])
|
||||
{
|
||||
backend->device_monitors[device_id] = meta_backend_create_idle_monitor (backend, device_id);
|
||||
backend->device_id_max = MAX (backend->device_id_max, device_id);
|
||||
}
|
||||
|
||||
return backend->device_monitors[device_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_get_monitor_manager: (skip)
|
||||
*/
|
||||
MetaMonitorManager *
|
||||
meta_backend_get_monitor_manager (MetaBackend *backend)
|
||||
{
|
||||
@ -168,6 +297,9 @@ meta_backend_get_monitor_manager (MetaBackend *backend)
|
||||
return priv->monitor_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_get_cursor_renderer: (skip)
|
||||
*/
|
||||
MetaCursorRenderer *
|
||||
meta_backend_get_cursor_renderer (MetaBackend *backend)
|
||||
{
|
||||
@ -176,6 +308,9 @@ meta_backend_get_cursor_renderer (MetaBackend *backend)
|
||||
return priv->cursor_renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_grab_device: (skip)
|
||||
*/
|
||||
gboolean
|
||||
meta_backend_grab_device (MetaBackend *backend,
|
||||
int device_id,
|
||||
@ -184,6 +319,9 @@ meta_backend_grab_device (MetaBackend *backend,
|
||||
return META_BACKEND_GET_CLASS (backend)->grab_device (backend, device_id, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_ungrab_device: (skip)
|
||||
*/
|
||||
gboolean
|
||||
meta_backend_ungrab_device (MetaBackend *backend,
|
||||
int device_id,
|
||||
@ -192,6 +330,9 @@ meta_backend_ungrab_device (MetaBackend *backend,
|
||||
return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_warp_pointer: (skip)
|
||||
*/
|
||||
void
|
||||
meta_backend_warp_pointer (MetaBackend *backend,
|
||||
int x,
|
||||
@ -200,6 +341,47 @@ meta_backend_warp_pointer (MetaBackend *backend,
|
||||
META_BACKEND_GET_CLASS (backend)->warp_pointer (backend, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_backend_set_keymap (MetaBackend *backend,
|
||||
const char *layouts,
|
||||
const char *variants,
|
||||
const char *options)
|
||||
{
|
||||
META_BACKEND_GET_CLASS (backend)->set_keymap (backend, layouts, variants, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_get_keymap: (skip)
|
||||
*/
|
||||
struct xkb_keymap *
|
||||
meta_backend_get_keymap (MetaBackend *backend)
|
||||
|
||||
{
|
||||
return META_BACKEND_GET_CLASS (backend)->get_keymap (backend);
|
||||
}
|
||||
|
||||
void
|
||||
meta_backend_lock_layout_group (MetaBackend *backend,
|
||||
guint idx)
|
||||
{
|
||||
META_BACKEND_GET_CLASS (backend)->lock_layout_group (backend, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_get_stage:
|
||||
* @backend: A #MetaBackend
|
||||
*
|
||||
* Gets the global #ClutterStage that's managed by this backend.
|
||||
*
|
||||
* Returns: (transfer none): the #ClutterStage
|
||||
*/
|
||||
ClutterActor *
|
||||
meta_backend_get_stage (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
return priv->stage;
|
||||
}
|
||||
|
||||
static GType
|
||||
get_backend_type (void)
|
||||
{
|
||||
@ -272,9 +454,13 @@ static GSourceFuncs event_funcs = {
|
||||
event_dispatch
|
||||
};
|
||||
|
||||
/**
|
||||
* meta_clutter_init: (skip)
|
||||
*/
|
||||
void
|
||||
meta_clutter_init (void)
|
||||
{
|
||||
ClutterSettings *clutter_settings;
|
||||
GSource *source;
|
||||
|
||||
meta_create_backend ();
|
||||
@ -282,6 +468,13 @@ meta_clutter_init (void)
|
||||
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
||||
g_error ("Unable to initialize Clutter.\n");
|
||||
|
||||
/*
|
||||
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
|
||||
* for now.
|
||||
*/
|
||||
clutter_settings = clutter_settings_get_default ();
|
||||
g_object_set (clutter_settings, "window-scaling-factor", 1, NULL);
|
||||
|
||||
source = g_source_new (&event_funcs, sizeof (GSource));
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
|
@ -27,14 +27,14 @@
|
||||
#include "meta-cursor-renderer.h"
|
||||
#include "meta-cursor-private.h"
|
||||
|
||||
#include <meta/meta-backend.h>
|
||||
#include <meta/util.h>
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "meta-stage.h"
|
||||
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
|
||||
struct _MetaCursorRendererPrivate
|
||||
{
|
||||
int current_x, current_y;
|
||||
@ -51,17 +51,20 @@ static void
|
||||
queue_redraw (MetaCursorRenderer *renderer)
|
||||
{
|
||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
ClutterActor *stage = compositor->stage;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||
CoglTexture *texture;
|
||||
|
||||
/* During early initialization, we can have no stage */
|
||||
if (!stage)
|
||||
return;
|
||||
|
||||
if (priv->handled_by_backend)
|
||||
meta_stage_set_cursor (META_STAGE (stage), NULL, &priv->current_rect);
|
||||
if (priv->displayed_cursor && !priv->handled_by_backend)
|
||||
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, NULL, NULL);
|
||||
else
|
||||
meta_stage_set_cursor (META_STAGE (stage), priv->displayed_cursor, &priv->current_rect);
|
||||
texture = NULL;
|
||||
|
||||
meta_stage_set_cursor (META_STAGE (stage), texture, &priv->current_rect);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -23,8 +23,6 @@
|
||||
#define META_CURSOR_TRACKER_PRIVATE_H
|
||||
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
#include <wayland-server.h>
|
||||
#include <gbm.h>
|
||||
|
||||
#include "meta-cursor.h"
|
||||
#include "meta-cursor-renderer.h"
|
||||
@ -32,7 +30,6 @@
|
||||
struct _MetaCursorTracker {
|
||||
GObject parent_instance;
|
||||
|
||||
MetaScreen *screen;
|
||||
MetaCursorRenderer *renderer;
|
||||
|
||||
gboolean is_showing;
|
||||
|
@ -34,25 +34,21 @@
|
||||
#include <meta/errors.h>
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include "meta-backend.h"
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
#include "meta-cursor-private.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "screen-private.h"
|
||||
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
|
||||
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
CURSOR_CHANGED,
|
||||
LAST_SIGNAL
|
||||
CURSOR_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
@ -60,10 +56,12 @@ static guint signals[LAST_SIGNAL];
|
||||
static MetaCursorReference *
|
||||
get_displayed_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
|
||||
if (!tracker->is_showing)
|
||||
return NULL;
|
||||
|
||||
if (tracker->screen->display->grab_op == META_GRAB_OP_NONE)
|
||||
if (meta_display_windows_are_interactable (display))
|
||||
{
|
||||
if (tracker->has_window_cursor)
|
||||
return tracker->window_cursor;
|
||||
@ -97,6 +95,9 @@ sync_cursor (MetaCursorTracker *tracker)
|
||||
static void
|
||||
meta_cursor_tracker_init (MetaCursorTracker *self)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
|
||||
self->renderer = meta_backend_get_cursor_renderer (backend);
|
||||
self->is_showing = TRUE;
|
||||
}
|
||||
|
||||
@ -129,47 +130,9 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
|
||||
}
|
||||
|
||||
static MetaCursorTracker *
|
||||
make_wayland_cursor_tracker (MetaScreen *screen)
|
||||
meta_cursor_tracker_new (void)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaWaylandCompositor *compositor;
|
||||
MetaCursorTracker *self;
|
||||
|
||||
self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
self->renderer = meta_backend_get_cursor_renderer (backend);
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
compositor->seat->pointer.cursor_tracker = self;
|
||||
meta_cursor_tracker_update_position (self, 0, 0);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static MetaCursorTracker *
|
||||
make_x11_cursor_tracker (MetaScreen *screen)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaCursorTracker *self;
|
||||
|
||||
self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
self->renderer = meta_backend_get_cursor_renderer (backend);
|
||||
|
||||
XFixesSelectCursorInput (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
XFixesDisplayCursorNotifyMask);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static MetaCursorTracker *
|
||||
meta_cursor_tracker_new (MetaScreen *screen)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
return make_wayland_cursor_tracker (screen);
|
||||
else
|
||||
return make_x11_cursor_tracker (screen);
|
||||
return g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
}
|
||||
|
||||
static MetaCursorTracker *_cursor_tracker;
|
||||
@ -186,7 +149,7 @@ MetaCursorTracker *
|
||||
meta_cursor_tracker_get_for_screen (MetaScreen *screen)
|
||||
{
|
||||
if (!_cursor_tracker)
|
||||
_cursor_tracker = meta_cursor_tracker_new (screen);
|
||||
_cursor_tracker = meta_cursor_tracker_new ();
|
||||
|
||||
return _cursor_tracker;
|
||||
}
|
||||
@ -207,12 +170,13 @@ gboolean
|
||||
meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||
XEvent *xevent)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
XFixesCursorNotifyEvent *notify_event;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
return FALSE;
|
||||
|
||||
if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify)
|
||||
if (xevent->xany.type != display->xfixes_event_base + XFixesCursorNotify)
|
||||
return FALSE;
|
||||
|
||||
notify_event = (XFixesCursorNotifyEvent *)xevent;
|
||||
@ -243,6 +207,7 @@ meta_cursor_reference_take_texture (CoglTexture2D *texture,
|
||||
static void
|
||||
ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
XFixesCursorImage *cursor_image;
|
||||
CoglTexture2D *sprite;
|
||||
guint8 *cursor_data;
|
||||
@ -252,7 +217,7 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
||||
if (tracker->xfixes_cursor)
|
||||
return;
|
||||
|
||||
cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay);
|
||||
cursor_image = XFixesGetCursorImage (display->xdisplay);
|
||||
if (!cursor_image)
|
||||
return;
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#include "display-private.h"
|
||||
#include "screen-private.h"
|
||||
#include "meta-backend.h"
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
#include "backends/native/meta-cursor-renderer-native.h"
|
||||
@ -39,7 +39,9 @@
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#endif
|
||||
|
||||
MetaCursorReference *
|
||||
meta_cursor_reference_ref (MetaCursorReference *self)
|
||||
@ -247,6 +249,7 @@ meta_cursor_reference_from_theme (MetaCursor cursor)
|
||||
return self;
|
||||
}
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
static void
|
||||
meta_cursor_image_load_from_buffer (MetaCursorImage *image,
|
||||
struct wl_resource *buffer,
|
||||
@ -345,6 +348,7 @@ meta_cursor_reference_from_buffer (struct wl_resource *buffer,
|
||||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
CoglTexture *
|
||||
meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
|
||||
|
@ -28,13 +28,15 @@ MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor);
|
||||
void meta_cursor_reference_unref (MetaCursorReference *cursor);
|
||||
|
||||
#include <meta/common.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
MetaCursorReference * meta_cursor_reference_from_theme (MetaCursor cursor);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include <wayland-server.h>
|
||||
MetaCursorReference * meta_cursor_reference_from_buffer (struct wl_resource *buffer,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
#endif
|
||||
|
||||
MetaCursor meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor);
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-idle-monitor-dbus.h"
|
||||
#include "meta-backend.h"
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
|
||||
|
||||
|
@ -60,7 +60,7 @@ typedef struct {
|
||||
gboolean enabled;
|
||||
MetaRectangle rect;
|
||||
float refresh_rate;
|
||||
enum wl_output_transform transform;
|
||||
MetaMonitorTransform transform;
|
||||
|
||||
gboolean is_primary;
|
||||
gboolean is_presentation;
|
||||
@ -656,20 +656,20 @@ handle_text (GMarkupParseContext *context,
|
||||
else if (strcmp (parser->output_field, "rotation") == 0)
|
||||
{
|
||||
if (strncmp (text, "normal", text_len) == 0)
|
||||
parser->output.transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
parser->output.transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
else if (strncmp (text, "left", text_len) == 0)
|
||||
parser->output.transform = WL_OUTPUT_TRANSFORM_90;
|
||||
parser->output.transform = META_MONITOR_TRANSFORM_90;
|
||||
else if (strncmp (text, "upside_down", text_len) == 0)
|
||||
parser->output.transform = WL_OUTPUT_TRANSFORM_180;
|
||||
parser->output.transform = META_MONITOR_TRANSFORM_180;
|
||||
else if (strncmp (text, "right", text_len) == 0)
|
||||
parser->output.transform = WL_OUTPUT_TRANSFORM_270;
|
||||
parser->output.transform = META_MONITOR_TRANSFORM_270;
|
||||
else
|
||||
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
|
||||
"Invalid rotation type %.*s", (int)text_len, text);
|
||||
}
|
||||
else if (strcmp (parser->output_field, "reflect_x") == 0)
|
||||
parser->output.transform += read_bool (text, text_len, error) ?
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED : 0;
|
||||
META_MONITOR_TRANSFORM_FLIPPED : 0;
|
||||
else if (strcmp (parser->output_field, "reflect_y") == 0)
|
||||
{
|
||||
/* FIXME (look at the rotation map in monitor.c) */
|
||||
@ -1115,7 +1115,7 @@ make_default_config (MetaMonitorConfig *self,
|
||||
ret->outputs[0].rect.width = outputs[0].preferred_mode->width;
|
||||
ret->outputs[0].rect.height = outputs[0].preferred_mode->height;
|
||||
ret->outputs[0].refresh_rate = outputs[0].preferred_mode->refresh_rate;
|
||||
ret->outputs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[0].transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
ret->outputs[0].is_primary = TRUE;
|
||||
|
||||
return ret;
|
||||
@ -1167,7 +1167,7 @@ make_default_config (MetaMonitorConfig *self,
|
||||
ret->outputs[j].rect.width = outputs[0].preferred_mode->width;
|
||||
ret->outputs[j].rect.height = outputs[0].preferred_mode->height;
|
||||
ret->outputs[j].refresh_rate = outputs[0].preferred_mode->refresh_rate;
|
||||
ret->outputs[j].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[j].transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
ret->outputs[j].is_primary = FALSE;
|
||||
ret->outputs[j].is_presentation = FALSE;
|
||||
}
|
||||
@ -1202,7 +1202,7 @@ make_default_config (MetaMonitorConfig *self,
|
||||
ret->outputs[i].rect.width = output->preferred_mode->width;
|
||||
ret->outputs[i].rect.height = output->preferred_mode->height;
|
||||
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
|
||||
ret->outputs[i].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
ret->outputs[i].is_primary = (output == primary);
|
||||
|
||||
/* Disable outputs that would go beyond framebuffer limits */
|
||||
@ -1250,7 +1250,7 @@ ensure_at_least_one_output (MetaMonitorConfig *self,
|
||||
ret->outputs[i].rect.width = output->preferred_mode->width;
|
||||
ret->outputs[i].rect.height = output->preferred_mode->height;
|
||||
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
|
||||
ret->outputs[i].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[i].transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
ret->outputs[i].is_primary = TRUE;
|
||||
}
|
||||
else
|
||||
@ -1512,7 +1512,7 @@ meta_monitor_config_save (MetaMonitorConfig *self)
|
||||
output->rect.x,
|
||||
output->rect.y,
|
||||
rotation_map[output->transform & 0x3],
|
||||
output->transform >= WL_OUTPUT_TRANSFORM_FLIPPED ? "yes" : "no",
|
||||
output->transform >= META_MONITOR_TRANSFORM_FLIPPED ? "yes" : "no",
|
||||
output->is_primary ? "yes" : "no",
|
||||
output->is_presentation ? "yes" : "no");
|
||||
}
|
||||
@ -1621,13 +1621,13 @@ output_supports_mode (MetaOutput *output,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
crtc_assignment_assign (CrtcAssignment *assign,
|
||||
MetaCRTC *crtc,
|
||||
MetaMonitorMode *mode,
|
||||
int x,
|
||||
int y,
|
||||
enum wl_output_transform transform,
|
||||
MetaOutput *output)
|
||||
crtc_assignment_assign (CrtcAssignment *assign,
|
||||
MetaCRTC *crtc,
|
||||
MetaMonitorMode *mode,
|
||||
int x,
|
||||
int y,
|
||||
MetaMonitorTransform transform,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaCRTCInfo *info = g_hash_table_lookup (assign->info, crtc);
|
||||
|
||||
@ -1789,7 +1789,6 @@ real_assign_crtcs (CrtcAssignment *assignment,
|
||||
output_config->transform,
|
||||
pass);
|
||||
|
||||
|
||||
if (crtc_assignment_assign (assignment, crtc, &modes[j],
|
||||
output_config->rect.x, output_config->rect.y,
|
||||
output_config->transform,
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#include "meta-monitor-manager-dummy.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
struct _MetaMonitorManagerDummy
|
||||
{
|
||||
@ -66,8 +66,8 @@ meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager)
|
||||
manager->crtcs[0].rect.width = manager->modes[0].width;
|
||||
manager->crtcs[0].rect.height = manager->modes[0].height;
|
||||
manager->crtcs[0].current_mode = &manager->modes[0];
|
||||
manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS;
|
||||
manager->crtcs[0].transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
manager->crtcs[0].all_transforms = ALL_TRANSFORMS;
|
||||
manager->crtcs[0].is_dirty = FALSE;
|
||||
manager->crtcs[0].logical_monitor = NULL;
|
||||
|
||||
@ -75,7 +75,7 @@ meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager)
|
||||
manager->n_outputs = 1;
|
||||
|
||||
manager->outputs[0].crtc = &manager->crtcs[0];
|
||||
manager->outputs[0].output_id = 1;
|
||||
manager->outputs[0].winsys_id = 1;
|
||||
manager->outputs[0].name = g_strdup ("LVDS");
|
||||
manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
|
||||
manager->outputs[0].product = g_strdup ("unknown");
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include <meta/errors.h>
|
||||
#include "meta-monitor-config.h"
|
||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
||||
#include "meta-backend.h"
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
enum {
|
||||
CONFIRM_DISPLAY_CHANGE,
|
||||
@ -125,7 +125,7 @@ make_logical_config (MetaMonitorManager *manager)
|
||||
*/
|
||||
info.is_presentation = TRUE;
|
||||
info.in_fullscreen = -1;
|
||||
info.output_id = 0;
|
||||
info.winsys_id = 0;
|
||||
|
||||
g_array_append_val (monitor_infos, info);
|
||||
|
||||
@ -156,8 +156,8 @@ make_logical_config (MetaMonitorManager *manager)
|
||||
info->is_primary = info->is_primary || output->is_primary;
|
||||
info->is_presentation = info->is_presentation && output->is_presentation;
|
||||
|
||||
if (output->is_primary || info->output_id == 0)
|
||||
info->output_id = output->output_id;
|
||||
if (output->is_primary || info->winsys_id == 0)
|
||||
info->winsys_id = output->winsys_id;
|
||||
|
||||
if (info->is_primary)
|
||||
manager->primary_monitor_index = info->number;
|
||||
@ -477,7 +477,7 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
||||
GVariantBuilder transforms;
|
||||
|
||||
g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
|
||||
for (j = 0; j <= WL_OUTPUT_TRANSFORM_FLIPPED_270; j++)
|
||||
for (j = 0; j <= META_MONITOR_TRANSFORM_FLIPPED_270; j++)
|
||||
if (crtc->all_transforms & (1 << j))
|
||||
g_variant_builder_add (&transforms, "u", j);
|
||||
|
||||
@ -560,7 +560,7 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
||||
|
||||
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
|
||||
i, /* ID */
|
||||
(gint64)output->output_id,
|
||||
(gint64)output->winsys_id,
|
||||
(int)(output->crtc ? output->crtc - manager->crtcs : -1),
|
||||
&crtcs,
|
||||
output->name,
|
||||
@ -667,7 +667,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
int new_mode, x, y;
|
||||
int new_screen_width, new_screen_height;
|
||||
guint transform;
|
||||
guint output_id;
|
||||
guint output_index;
|
||||
GPtrArray *crtc_infos, *output_infos;
|
||||
|
||||
if (serial != manager->serial)
|
||||
@ -694,7 +694,6 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
MetaOutput *first_output;
|
||||
MetaCRTC *crtc;
|
||||
MetaMonitorMode *mode;
|
||||
guint output_id;
|
||||
|
||||
crtc_info = g_slice_new (MetaCRTCInfo);
|
||||
crtc_info->outputs = g_ptr_array_new ();
|
||||
@ -756,8 +755,8 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
crtc_info->y = 0;
|
||||
}
|
||||
|
||||
if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
|
||||
transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 ||
|
||||
if (transform < META_MONITOR_TRANSFORM_NORMAL ||
|
||||
transform > META_MONITOR_TRANSFORM_FLIPPED_270 ||
|
||||
((crtc->all_transforms & (1 << transform)) == 0))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
@ -768,18 +767,18 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
crtc_info->transform = transform;
|
||||
|
||||
first_output = NULL;
|
||||
while (g_variant_iter_loop (nested_outputs, "u", &output_id))
|
||||
while (g_variant_iter_loop (nested_outputs, "u", &output_index))
|
||||
{
|
||||
MetaOutput *output;
|
||||
|
||||
if (output_id >= manager->n_outputs)
|
||||
if (output_index >= manager->n_outputs)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid output id");
|
||||
return TRUE;
|
||||
}
|
||||
output = &manager->outputs[output_id];
|
||||
output = &manager->outputs[output_index];
|
||||
|
||||
if (!output_can_config (output, crtc, mode))
|
||||
{
|
||||
@ -824,12 +823,12 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
}
|
||||
|
||||
g_variant_iter_init (&output_iter, outputs);
|
||||
while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_id, &properties))
|
||||
while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_index, &properties))
|
||||
{
|
||||
MetaOutputInfo *output_info;
|
||||
gboolean primary, presentation;
|
||||
|
||||
if (output_id >= manager->n_outputs)
|
||||
if (output_index >= manager->n_outputs)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
@ -838,7 +837,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
}
|
||||
|
||||
output_info = g_slice_new0 (MetaOutputInfo);
|
||||
output_info->output = &manager->outputs[output_id];
|
||||
output_info->output = &manager->outputs[output_index];
|
||||
|
||||
if (g_variant_lookup (properties, "primary", "b", &primary))
|
||||
output_info->is_primary = primary;
|
||||
@ -909,7 +908,7 @@ static gboolean
|
||||
meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint serial,
|
||||
guint output_id,
|
||||
guint output_index,
|
||||
gint value)
|
||||
{
|
||||
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
|
||||
@ -923,14 +922,14 @@ meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (output_id >= manager->n_outputs)
|
||||
if (output_index >= manager->n_outputs)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid output id");
|
||||
return TRUE;
|
||||
}
|
||||
output = &manager->outputs[output_id];
|
||||
output = &manager->outputs[output_index];
|
||||
|
||||
if (value < 0 || value > 100)
|
||||
{
|
||||
|
@ -41,8 +41,6 @@
|
||||
#include "display-private.h"
|
||||
#include <meta/screen.h>
|
||||
#include "stack-tracker.h"
|
||||
#include "ui.h"
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "meta-display-config-shared.h"
|
||||
#include "meta-dbus-display-config.h"
|
||||
@ -60,12 +58,23 @@ typedef struct _MetaMonitorInfo MetaMonitorInfo;
|
||||
typedef struct _MetaCRTCInfo MetaCRTCInfo;
|
||||
typedef struct _MetaOutputInfo MetaOutputInfo;
|
||||
|
||||
typedef enum {
|
||||
META_MONITOR_TRANSFORM_NORMAL,
|
||||
META_MONITOR_TRANSFORM_90,
|
||||
META_MONITOR_TRANSFORM_180,
|
||||
META_MONITOR_TRANSFORM_270,
|
||||
META_MONITOR_TRANSFORM_FLIPPED,
|
||||
META_MONITOR_TRANSFORM_FLIPPED_90,
|
||||
META_MONITOR_TRANSFORM_FLIPPED_180,
|
||||
META_MONITOR_TRANSFORM_FLIPPED_270,
|
||||
} MetaMonitorTransform;
|
||||
|
||||
struct _MetaOutput
|
||||
{
|
||||
/* The CRTC driving this output, NULL if the output is not enabled */
|
||||
MetaCRTC *crtc;
|
||||
/* The low-level ID of this output, used to apply back configuration */
|
||||
glong output_id;
|
||||
glong winsys_id;
|
||||
char *name;
|
||||
char *vendor;
|
||||
char *product;
|
||||
@ -114,7 +123,7 @@ struct _MetaCRTC
|
||||
glong crtc_id;
|
||||
MetaRectangle rect;
|
||||
MetaMonitorMode *current_mode;
|
||||
enum wl_output_transform transform;
|
||||
MetaMonitorTransform transform;
|
||||
unsigned int all_transforms;
|
||||
|
||||
/* Only used to build the logical configuration
|
||||
@ -162,14 +171,14 @@ struct _MetaMonitorInfo
|
||||
gboolean in_fullscreen;
|
||||
|
||||
/* The primary or first output for this monitor, 0 if we can't figure out.
|
||||
It can be matched to an output_id of a MetaOutput.
|
||||
It can be matched to a winsys_id of a MetaOutput.
|
||||
|
||||
This is used as an opaque token on reconfiguration when switching from
|
||||
clone to extened, to decide on what output the windows should go next
|
||||
(it's an attempt to keep windows on the same monitor, and preferably on
|
||||
the primary one).
|
||||
*/
|
||||
glong output_id;
|
||||
glong winsys_id;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -185,7 +194,7 @@ struct _MetaCRTCInfo {
|
||||
MetaMonitorMode *mode;
|
||||
int x;
|
||||
int y;
|
||||
enum wl_output_transform transform;
|
||||
MetaMonitorTransform transform;
|
||||
GPtrArray *outputs;
|
||||
};
|
||||
|
||||
@ -339,7 +348,7 @@ gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorMana
|
||||
/* Returns true if transform causes width and height to be inverted
|
||||
This is true for the odd transforms in the enum */
|
||||
static inline gboolean
|
||||
meta_monitor_transform_is_rotated (enum wl_output_transform transform)
|
||||
meta_monitor_transform_is_rotated (MetaMonitorTransform transform)
|
||||
{
|
||||
return (transform % 2);
|
||||
}
|
||||
|
@ -25,35 +25,85 @@
|
||||
#include "meta-stage.h"
|
||||
|
||||
#include "meta-cursor-private.h"
|
||||
#include "meta-backend.h"
|
||||
#include <meta/meta-backend.h>
|
||||
#include <meta/util.h>
|
||||
|
||||
struct _MetaStagePrivate {
|
||||
CoglPipeline *pipeline;
|
||||
gboolean should_paint_cursor;
|
||||
typedef struct {
|
||||
gboolean enabled;
|
||||
|
||||
MetaCursorReference *cursor;
|
||||
CoglPipeline *pipeline;
|
||||
CoglTexture *texture;
|
||||
|
||||
MetaRectangle current_rect;
|
||||
MetaRectangle previous_rect;
|
||||
gboolean previous_is_valid;
|
||||
} MetaOverlay;
|
||||
|
||||
struct _MetaStagePrivate {
|
||||
MetaOverlay cursor_overlay;
|
||||
};
|
||||
typedef struct _MetaStagePrivate MetaStagePrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaStage, meta_stage, CLUTTER_TYPE_STAGE);
|
||||
|
||||
static void
|
||||
update_pipeline (MetaStage *stage)
|
||||
meta_overlay_init (MetaOverlay *overlay)
|
||||
{
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
|
||||
if (priv->cursor)
|
||||
overlay->pipeline = cogl_pipeline_new (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_overlay_free (MetaOverlay *overlay)
|
||||
{
|
||||
if (overlay->pipeline)
|
||||
cogl_object_unref (overlay->pipeline);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_overlay_set (MetaOverlay *overlay,
|
||||
CoglTexture *texture,
|
||||
MetaRectangle *rect)
|
||||
{
|
||||
if (overlay->texture != texture)
|
||||
{
|
||||
CoglTexture *texture = meta_cursor_reference_get_cogl_texture (priv->cursor, NULL, NULL);
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
|
||||
overlay->texture = texture;
|
||||
|
||||
if (texture)
|
||||
{
|
||||
cogl_pipeline_set_layer_texture (overlay->pipeline, 0, texture);
|
||||
overlay->enabled = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
cogl_pipeline_set_layer_texture (overlay->pipeline, 0, NULL);
|
||||
overlay->enabled = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, NULL);
|
||||
|
||||
overlay->current_rect = *rect;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_overlay_paint (MetaOverlay *overlay)
|
||||
{
|
||||
if (!overlay->enabled)
|
||||
return;
|
||||
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
|
||||
overlay->pipeline,
|
||||
overlay->current_rect.x,
|
||||
overlay->current_rect.y,
|
||||
overlay->current_rect.x +
|
||||
overlay->current_rect.width,
|
||||
overlay->current_rect.y +
|
||||
overlay->current_rect.height);
|
||||
|
||||
overlay->previous_rect = overlay->current_rect;
|
||||
overlay->previous_is_valid = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -62,42 +112,18 @@ meta_stage_finalize (GObject *object)
|
||||
MetaStage *stage = META_STAGE (object);
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
|
||||
if (priv->pipeline)
|
||||
cogl_object_unref (priv->pipeline);
|
||||
}
|
||||
|
||||
static void
|
||||
paint_cursor (MetaStage *stage)
|
||||
{
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
if (!priv->cursor)
|
||||
return;
|
||||
|
||||
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
|
||||
priv->pipeline,
|
||||
priv->current_rect.x,
|
||||
priv->current_rect.y,
|
||||
priv->current_rect.x +
|
||||
priv->current_rect.width,
|
||||
priv->current_rect.y +
|
||||
priv->current_rect.height);
|
||||
|
||||
priv->previous_rect = priv->current_rect;
|
||||
priv->previous_is_valid = TRUE;
|
||||
meta_overlay_free (&priv->cursor_overlay);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_stage_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaStage *stage = META_STAGE (actor);
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
paint_cursor (stage);
|
||||
meta_overlay_paint (&priv->cursor_overlay);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -114,10 +140,9 @@ meta_stage_class_init (MetaStageClass *klass)
|
||||
static void
|
||||
meta_stage_init (MetaStage *stage)
|
||||
{
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
|
||||
priv->pipeline = cogl_pipeline_new (ctx);
|
||||
meta_overlay_init (&priv->cursor_overlay);
|
||||
|
||||
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
|
||||
}
|
||||
@ -131,46 +156,42 @@ meta_stage_new (void)
|
||||
}
|
||||
|
||||
static void
|
||||
queue_redraw (MetaStage *stage)
|
||||
queue_redraw_for_overlay (MetaStage *stage,
|
||||
MetaOverlay *overlay)
|
||||
{
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
cairo_rectangle_int_t clip;
|
||||
|
||||
/* Clear the location the cursor was at before, if we need to. */
|
||||
if (priv->previous_is_valid)
|
||||
/* Clear the location the overlay was at before, if we need to. */
|
||||
if (overlay->previous_is_valid)
|
||||
{
|
||||
clip.x = priv->previous_rect.x;
|
||||
clip.y = priv->previous_rect.y;
|
||||
clip.width = priv->previous_rect.width;
|
||||
clip.height = priv->previous_rect.height;
|
||||
clip.x = overlay->previous_rect.x;
|
||||
clip.y = overlay->previous_rect.y;
|
||||
clip.width = overlay->previous_rect.width;
|
||||
clip.height = overlay->previous_rect.height;
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
|
||||
priv->previous_is_valid = FALSE;
|
||||
overlay->previous_is_valid = FALSE;
|
||||
}
|
||||
|
||||
/* And queue a redraw for the current cursor location. */
|
||||
if (priv->cursor)
|
||||
/* Draw the overlay at the new position */
|
||||
if (overlay->enabled)
|
||||
{
|
||||
clip.x = priv->current_rect.x;
|
||||
clip.y = priv->current_rect.y;
|
||||
clip.width = priv->current_rect.width;
|
||||
clip.height = priv->current_rect.height;
|
||||
clip.x = overlay->current_rect.x;
|
||||
clip.y = overlay->current_rect.y;
|
||||
clip.width = overlay->current_rect.width;
|
||||
clip.height = overlay->current_rect.height;
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_stage_set_cursor (MetaStage *stage,
|
||||
MetaCursorReference *cursor,
|
||||
MetaRectangle *rect)
|
||||
meta_stage_set_cursor (MetaStage *stage,
|
||||
CoglTexture *texture,
|
||||
MetaRectangle *rect)
|
||||
{
|
||||
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
|
||||
|
||||
if (priv->cursor != cursor)
|
||||
{
|
||||
priv->cursor = cursor;
|
||||
update_pipeline (stage);
|
||||
}
|
||||
g_assert (meta_is_wayland_compositor () || texture == NULL);
|
||||
|
||||
priv->current_rect = *rect;
|
||||
queue_redraw (stage);
|
||||
meta_overlay_set (&priv->cursor_overlay, texture, rect);
|
||||
queue_redraw_for_overlay (stage, &priv->cursor_overlay);
|
||||
}
|
@ -51,9 +51,9 @@ GType meta_stage_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *meta_stage_new (void);
|
||||
|
||||
void meta_stage_set_cursor (MetaStage *stage,
|
||||
MetaCursorReference *cursor,
|
||||
MetaRectangle *rect);
|
||||
void meta_stage_set_cursor (MetaStage *stage,
|
||||
CoglTexture *texture,
|
||||
MetaRectangle *rect);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_STAGE_H */
|
@ -188,6 +188,50 @@ meta_backend_native_warp_pointer (MetaBackend *backend,
|
||||
clutter_evdev_warp_pointer (device, time_, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_native_set_keymap (MetaBackend *backend,
|
||||
const char *layouts,
|
||||
const char *variants,
|
||||
const char *options)
|
||||
{
|
||||
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
|
||||
struct xkb_rule_names names;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_context *context;
|
||||
|
||||
names.rules = DEFAULT_XKB_RULES_FILE;
|
||||
names.model = DEFAULT_XKB_MODEL;
|
||||
names.layout = layouts;
|
||||
names.variant = variants;
|
||||
names.options = options;
|
||||
|
||||
context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
|
||||
keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
xkb_context_unref (context);
|
||||
|
||||
clutter_evdev_set_keyboard_map (manager, keymap);
|
||||
|
||||
g_signal_emit_by_name (backend, "keymap-changed", 0);
|
||||
|
||||
xkb_keymap_unref (keymap);
|
||||
}
|
||||
|
||||
static struct xkb_keymap *
|
||||
meta_backend_native_get_keymap (MetaBackend *backend)
|
||||
{
|
||||
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
|
||||
return clutter_evdev_get_keyboard_map (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_native_lock_layout_group (MetaBackend *backend,
|
||||
guint idx)
|
||||
{
|
||||
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
|
||||
clutter_evdev_set_keyboard_layout_index (manager, idx);
|
||||
g_signal_emit_by_name (backend, "keymap-layout-group-changed", idx, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_native_class_init (MetaBackendNativeClass *klass)
|
||||
{
|
||||
@ -199,6 +243,9 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
|
||||
backend_class->create_cursor_renderer = meta_backend_native_create_cursor_renderer;
|
||||
|
||||
backend_class->warp_pointer = meta_backend_native_warp_pointer;
|
||||
backend_class->set_keymap = meta_backend_native_set_keymap;
|
||||
backend_class->get_keymap = meta_backend_native_get_keymap;
|
||||
backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -41,8 +41,7 @@
|
||||
#include "dbus-utils.h"
|
||||
#include "meta-dbus-login1.h"
|
||||
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#include "backends/meta-backend.h"
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "meta-cursor-renderer-native.h"
|
||||
|
||||
struct _MetaLauncher
|
||||
@ -101,15 +100,15 @@ session_unpause (void)
|
||||
clutter_egl_thaw_master_clock ();
|
||||
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (backend);
|
||||
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||
|
||||
/* When we mode-switch back, we need to immediately queue a redraw
|
||||
* in case nothing else queued one for us, and force the cursor to
|
||||
* update. */
|
||||
|
||||
clutter_actor_queue_redraw (compositor->stage);
|
||||
clutter_actor_queue_redraw (stage);
|
||||
meta_cursor_renderer_native_force_update (META_CURSOR_RENDERER_NATIVE (renderer));
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,6 @@
|
||||
#include <meta/errors.h>
|
||||
#include "edid.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
typedef struct {
|
||||
drmModeConnector *connector;
|
||||
|
||||
@ -259,7 +257,7 @@ find_output_by_id (MetaOutput *outputs,
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
if (outputs[i].output_id == id)
|
||||
if (outputs[i].winsys_id == id)
|
||||
return &outputs[i];
|
||||
|
||||
return NULL;
|
||||
@ -363,9 +361,9 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||
meta_crtc->rect.width = crtc->width;
|
||||
meta_crtc->rect.height = crtc->height;
|
||||
meta_crtc->is_dirty = FALSE;
|
||||
meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
meta_crtc->transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
/* FIXME: implement! */
|
||||
meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
meta_crtc->all_transforms = 1 << META_MONITOR_TRANSFORM_NORMAL;
|
||||
|
||||
if (crtc->mode_valid)
|
||||
{
|
||||
@ -408,7 +406,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||
meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms);
|
||||
meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
|
||||
|
||||
meta_output->output_id = connector->connector_id;
|
||||
meta_output->winsys_id = connector->connector_id;
|
||||
meta_output->name = make_output_name (connector);
|
||||
meta_output->width_mm = connector->mmWidth;
|
||||
meta_output->height_mm = connector->mmHeight;
|
||||
@ -491,7 +489,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||
meta_output->crtc = NULL;
|
||||
|
||||
old_output = find_output_by_id (old_outputs, n_old_outputs,
|
||||
meta_output->output_id);
|
||||
meta_output->winsys_id);
|
||||
if (old_output)
|
||||
{
|
||||
meta_output->is_primary = old_output->is_primary;
|
||||
@ -667,7 +665,7 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
|
||||
if (output_kms->dpms_prop_id != 0)
|
||||
{
|
||||
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id,
|
||||
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->winsys_id,
|
||||
output_kms->dpms_prop_id, state);
|
||||
|
||||
if (ok < 0)
|
||||
@ -748,7 +746,7 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
|
||||
{
|
||||
MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j);
|
||||
|
||||
connectors[j] = output->output_id;
|
||||
connectors[j] = output->winsys_id;
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
|
@ -24,11 +24,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "meta-backend-x11.h"
|
||||
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
|
||||
#include <X11/extensions/sync.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/XKBrules.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
#include "meta-idle-monitor-xsync.h"
|
||||
#include "meta-monitor-manager-xrandr.h"
|
||||
@ -43,6 +50,7 @@ struct _MetaBackendX11Private
|
||||
{
|
||||
/* The host X11 display */
|
||||
Display *xdisplay;
|
||||
xcb_connection_t *xcb;
|
||||
GSource *source;
|
||||
|
||||
int xsync_event_base;
|
||||
@ -51,6 +59,12 @@ struct _MetaBackendX11Private
|
||||
int xinput_opcode;
|
||||
int xinput_event_base;
|
||||
int xinput_error_base;
|
||||
Time latest_evtime;
|
||||
|
||||
uint8_t xkb_event_base;
|
||||
uint8_t xkb_error_base;
|
||||
|
||||
struct xkb_keymap *keymap;
|
||||
};
|
||||
typedef struct _MetaBackendX11Private MetaBackendX11Private;
|
||||
|
||||
@ -71,6 +85,7 @@ static void
|
||||
translate_device_event (MetaBackendX11 *x11,
|
||||
XIDeviceEvent *device_event)
|
||||
{
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
Window stage_window = meta_backend_x11_get_xwindow (x11);
|
||||
|
||||
if (device_event->event != stage_window)
|
||||
@ -88,6 +103,21 @@ translate_device_event (MetaBackendX11 *x11,
|
||||
device_event->event_x = device_event->root_x;
|
||||
device_event->event_y = device_event->root_y;
|
||||
}
|
||||
|
||||
if (!device_event->send_event && device_event->time != CurrentTime)
|
||||
{
|
||||
if (device_event->time < priv->latest_evtime)
|
||||
{
|
||||
/* Emulated pointer events received after XIRejectTouch is received
|
||||
* on a passive touch grab will contain older timestamps, update those
|
||||
* so we dont get InvalidTime at grabs.
|
||||
*/
|
||||
device_event->time = priv->latest_evtime;
|
||||
}
|
||||
|
||||
/* Update the internal latest evtime, for any possible later use */
|
||||
priv->latest_evtime = device_event->time;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clutter makes the assumption that there is only one X window
|
||||
@ -117,6 +147,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
|
||||
case XI_ButtonRelease:
|
||||
case XI_KeyPress:
|
||||
case XI_KeyRelease:
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchEnd:
|
||||
translate_device_event (x11, (XIDeviceEvent *) input_event);
|
||||
break;
|
||||
default:
|
||||
@ -125,6 +158,21 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
keymap_changed (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
|
||||
if (priv->keymap)
|
||||
{
|
||||
xkb_keymap_unref (priv->keymap);
|
||||
priv->keymap = NULL;
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (backend, "keymap-changed", 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_host_xevent (MetaBackend *backend,
|
||||
XEvent *event)
|
||||
@ -135,24 +183,49 @@ handle_host_xevent (MetaBackend *backend,
|
||||
|
||||
XGetEventData (priv->xdisplay, &event->xcookie);
|
||||
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
|
||||
if (display)
|
||||
{
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
|
||||
bypass_clutter = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type == (priv->xsync_event_base + XSyncAlarmNotify))
|
||||
handle_alarm_notify (backend, event);
|
||||
|
||||
if (event->type == priv->xkb_event_base)
|
||||
{
|
||||
XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
|
||||
|
||||
if (xkb_ev->device == META_VIRTUAL_CORE_KEYBOARD_ID)
|
||||
{
|
||||
switch (xkb_ev->xkb_type)
|
||||
{
|
||||
case XkbNewKeyboardNotify:
|
||||
case XkbMapNotify:
|
||||
keymap_changed (backend);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend);
|
||||
if (META_IS_MONITOR_MANAGER_XRANDR (manager) &&
|
||||
meta_monitor_manager_xrandr_handle_xevent (META_MONITOR_MANAGER_XRANDR (manager), event))
|
||||
{
|
||||
bypass_clutter = TRUE;
|
||||
goto out;
|
||||
}
|
||||
bypass_clutter = TRUE;
|
||||
}
|
||||
|
||||
maybe_spoof_event_as_stage_event (x11, event);
|
||||
|
||||
out:
|
||||
if (!bypass_clutter)
|
||||
clutter_x11_handle_event (event);
|
||||
{
|
||||
maybe_spoof_event_as_stage_event (x11, event);
|
||||
clutter_x11_handle_event (event);
|
||||
}
|
||||
|
||||
XFreeEventData (priv->xdisplay, &event->xcookie);
|
||||
}
|
||||
@ -235,6 +308,24 @@ x_event_source_new (MetaBackend *backend)
|
||||
return source;
|
||||
}
|
||||
|
||||
static void
|
||||
take_touch_grab (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { META_VIRTUAL_CORE_POINTER_ID, sizeof (mask_bits), mask_bits };
|
||||
XIGrabModifiers mods = { XIAnyModifier, 0 };
|
||||
|
||||
XISetMask (mask.mask, XI_TouchBegin);
|
||||
XISetMask (mask.mask, XI_TouchUpdate);
|
||||
XISetMask (mask.mask, XI_TouchEnd);
|
||||
|
||||
XIGrabTouchBegin (priv->xdisplay, META_VIRTUAL_CORE_POINTER_ID,
|
||||
DefaultRootWindow (priv->xdisplay),
|
||||
False, &mask, 1, &mods);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_post_init (MetaBackend *backend)
|
||||
{
|
||||
@ -272,6 +363,19 @@ meta_backend_x11_post_init (MetaBackend *backend)
|
||||
meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n");
|
||||
}
|
||||
|
||||
take_touch_grab (backend);
|
||||
|
||||
priv->xcb = XGetXCBConnection (priv->xdisplay);
|
||||
if (!xkb_x11_setup_xkb_extension (priv->xcb,
|
||||
XKB_X11_MIN_MAJOR_XKB_VERSION,
|
||||
XKB_X11_MIN_MINOR_XKB_VERSION,
|
||||
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
|
||||
NULL, NULL,
|
||||
&priv->xkb_event_base,
|
||||
&priv->xkb_error_base))
|
||||
meta_fatal ("X server doesn't have the XKB extension, version %d.%d or newer\n",
|
||||
XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION);
|
||||
|
||||
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
|
||||
}
|
||||
|
||||
@ -313,6 +417,9 @@ meta_backend_x11_grab_device (MetaBackend *backend,
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
int ret;
|
||||
|
||||
if (timestamp != CurrentTime)
|
||||
timestamp = MAX (timestamp, priv->latest_evtime);
|
||||
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
@ -362,6 +469,208 @@ meta_backend_x11_warp_pointer (MetaBackend *backend,
|
||||
x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
get_xkbrf_var_defs (Display *xdisplay,
|
||||
const char *layouts,
|
||||
const char *variants,
|
||||
const char *options,
|
||||
char **rules_p,
|
||||
XkbRF_VarDefsRec *var_defs)
|
||||
{
|
||||
char *rules = NULL;
|
||||
|
||||
/* Get it from the X property or fallback on defaults */
|
||||
if (!XkbRF_GetNamesProp (xdisplay, &rules, var_defs) || !rules)
|
||||
{
|
||||
rules = strdup (DEFAULT_XKB_RULES_FILE);
|
||||
var_defs->model = strdup (DEFAULT_XKB_MODEL);
|
||||
var_defs->layout = NULL;
|
||||
var_defs->variant = NULL;
|
||||
var_defs->options = NULL;
|
||||
}
|
||||
|
||||
/* Swap in our new options... */
|
||||
free (var_defs->layout);
|
||||
var_defs->layout = strdup (layouts);
|
||||
free (var_defs->variant);
|
||||
var_defs->variant = strdup (variants);
|
||||
free (var_defs->options);
|
||||
var_defs->options = strdup (options);
|
||||
|
||||
/* Sometimes, the property is a file path, and sometimes it's
|
||||
not. Normalize it so it's always a file path. */
|
||||
if (rules[0] == '/')
|
||||
*rules_p = g_strdup (rules);
|
||||
else
|
||||
*rules_p = g_build_filename (XKB_BASE, "rules", rules, NULL);
|
||||
|
||||
free (rules);
|
||||
}
|
||||
|
||||
static void
|
||||
free_xkbrf_var_defs (XkbRF_VarDefsRec *var_defs)
|
||||
{
|
||||
free (var_defs->model);
|
||||
free (var_defs->layout);
|
||||
free (var_defs->variant);
|
||||
free (var_defs->options);
|
||||
}
|
||||
|
||||
static void
|
||||
free_xkb_component_names (XkbComponentNamesRec *p)
|
||||
{
|
||||
free (p->keymap);
|
||||
free (p->keycodes);
|
||||
free (p->types);
|
||||
free (p->compat);
|
||||
free (p->symbols);
|
||||
free (p->geometry);
|
||||
}
|
||||
|
||||
static void
|
||||
upload_xkb_description (Display *xdisplay,
|
||||
const gchar *rules_file_path,
|
||||
XkbRF_VarDefsRec *var_defs,
|
||||
XkbComponentNamesRec *comp_names)
|
||||
{
|
||||
XkbDescRec *xkb_desc;
|
||||
gchar *rules_file;
|
||||
|
||||
/* Upload it to the X server using the same method as setxkbmap */
|
||||
xkb_desc = XkbGetKeyboardByName (xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
comp_names,
|
||||
XkbGBN_AllComponentsMask,
|
||||
XkbGBN_AllComponentsMask &
|
||||
(~XkbGBN_GeometryMask), True);
|
||||
if (!xkb_desc)
|
||||
{
|
||||
g_warning ("Couldn't upload new XKB keyboard description");
|
||||
return;
|
||||
}
|
||||
|
||||
XkbFreeKeyboard (xkb_desc, 0, True);
|
||||
|
||||
rules_file = g_path_get_basename (rules_file_path);
|
||||
|
||||
if (!XkbRF_SetNamesProp (xdisplay, rules_file, var_defs))
|
||||
g_warning ("Couldn't update the XKB root window property");
|
||||
|
||||
g_free (rules_file);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_set_keymap (MetaBackend *backend,
|
||||
const char *layouts,
|
||||
const char *variants,
|
||||
const char *options)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
XkbRF_RulesRec *xkb_rules;
|
||||
XkbRF_VarDefsRec xkb_var_defs = { 0 };
|
||||
gchar *rules_file_path;
|
||||
|
||||
get_xkbrf_var_defs (priv->xdisplay,
|
||||
layouts,
|
||||
variants,
|
||||
options,
|
||||
&rules_file_path,
|
||||
&xkb_var_defs);
|
||||
|
||||
xkb_rules = XkbRF_Load (rules_file_path, NULL, True, True);
|
||||
if (xkb_rules)
|
||||
{
|
||||
XkbComponentNamesRec xkb_comp_names = { 0 };
|
||||
|
||||
XkbRF_GetComponents (xkb_rules, &xkb_var_defs, &xkb_comp_names);
|
||||
upload_xkb_description (priv->xdisplay, rules_file_path, &xkb_var_defs, &xkb_comp_names);
|
||||
|
||||
free_xkb_component_names (&xkb_comp_names);
|
||||
XkbRF_Free (xkb_rules, True);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Couldn't load XKB rules");
|
||||
}
|
||||
|
||||
free_xkbrf_var_defs (&xkb_var_defs);
|
||||
g_free (rules_file_path);
|
||||
}
|
||||
|
||||
static struct xkb_keymap *
|
||||
meta_backend_x11_get_keymap (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
|
||||
if (priv->keymap == NULL)
|
||||
{
|
||||
struct xkb_context *context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
|
||||
priv->keymap = xkb_x11_keymap_new_from_device (context,
|
||||
priv->xcb,
|
||||
xkb_x11_get_core_keyboard_device_id (priv->xcb),
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
xkb_context_unref (context);
|
||||
}
|
||||
|
||||
return priv->keymap;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_lock_layout_group (MetaBackend *backend,
|
||||
guint idx)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
|
||||
XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_update_screen_size (MetaBackend *backend,
|
||||
int width, int height)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* For a nested wayland session, we want to go through Clutter to update the
|
||||
* toplevel window size, rather than doing it directly.
|
||||
*/
|
||||
META_BACKEND_CLASS (meta_backend_x11_parent_class)->update_screen_size (backend, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
Window xwin = meta_backend_x11_get_xwindow (x11);
|
||||
XResizeWindow (priv->xdisplay, xwin, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_select_stage_events (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
|
||||
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
|
||||
Window xwin = meta_backend_x11_get_xwindow (x11);
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XIClearMask (mask.mask, XI_TouchBegin);
|
||||
XIClearMask (mask.mask, XI_TouchEnd);
|
||||
XIClearMask (mask.mask, XI_TouchUpdate);
|
||||
XISelectEvents (priv->xdisplay, xwin, &mask, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_backend_x11_class_init (MetaBackendX11Class *klass)
|
||||
{
|
||||
@ -371,10 +680,14 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
|
||||
backend_class->create_idle_monitor = meta_backend_x11_create_idle_monitor;
|
||||
backend_class->create_monitor_manager = meta_backend_x11_create_monitor_manager;
|
||||
backend_class->create_cursor_renderer = meta_backend_x11_create_cursor_renderer;
|
||||
|
||||
backend_class->grab_device = meta_backend_x11_grab_device;
|
||||
backend_class->ungrab_device = meta_backend_x11_ungrab_device;
|
||||
backend_class->warp_pointer = meta_backend_x11_warp_pointer;
|
||||
backend_class->set_keymap = meta_backend_x11_set_keymap;
|
||||
backend_class->get_keymap = meta_backend_x11_get_keymap;
|
||||
backend_class->lock_layout_group = meta_backend_x11_lock_layout_group;
|
||||
backend_class->update_screen_size = meta_backend_x11_update_screen_size;
|
||||
backend_class->select_stage_events = meta_backend_x11_select_stage_events;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -395,12 +708,6 @@ meta_backend_x11_get_xdisplay (MetaBackendX11 *x11)
|
||||
Window
|
||||
meta_backend_x11_get_xwindow (MetaBackendX11 *x11)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
|
||||
if (compositor == NULL)
|
||||
return None;
|
||||
|
||||
ClutterStage *stage = CLUTTER_STAGE (compositor->stage);
|
||||
return clutter_x11_get_stage_window (stage);
|
||||
ClutterActor *stage = meta_backend_get_stage (META_BACKEND (x11));
|
||||
return clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
|
||||
}
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/dpms.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <xcb/randr.h>
|
||||
|
||||
#include "meta-backend-x11.h"
|
||||
#include <meta/main.h>
|
||||
@ -42,7 +44,7 @@
|
||||
#include "edid.h"
|
||||
#include "meta-monitor-config.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
#define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
/* Look for DPI_FALLBACK in:
|
||||
* http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
|
||||
@ -67,31 +69,31 @@ struct _MetaMonitorManagerXrandrClass
|
||||
|
||||
G_DEFINE_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr, META_TYPE_MONITOR_MANAGER);
|
||||
|
||||
static enum wl_output_transform
|
||||
wl_transform_from_xrandr (Rotation rotation)
|
||||
static MetaMonitorTransform
|
||||
meta_monitor_transform_from_xrandr (Rotation rotation)
|
||||
{
|
||||
static const enum wl_output_transform y_reflected_map[4] = {
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_180,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_90,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_270
|
||||
static const MetaMonitorTransform y_reflected_map[4] = {
|
||||
META_MONITOR_TRANSFORM_FLIPPED_180,
|
||||
META_MONITOR_TRANSFORM_FLIPPED_90,
|
||||
META_MONITOR_TRANSFORM_FLIPPED,
|
||||
META_MONITOR_TRANSFORM_FLIPPED_270
|
||||
};
|
||||
enum wl_output_transform ret;
|
||||
MetaMonitorTransform ret;
|
||||
|
||||
switch (rotation & 0x7F)
|
||||
{
|
||||
default:
|
||||
case RR_Rotate_0:
|
||||
ret = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret = META_MONITOR_TRANSFORM_NORMAL;
|
||||
break;
|
||||
case RR_Rotate_90:
|
||||
ret = WL_OUTPUT_TRANSFORM_90;
|
||||
ret = META_MONITOR_TRANSFORM_90;
|
||||
break;
|
||||
case RR_Rotate_180:
|
||||
ret = WL_OUTPUT_TRANSFORM_180;
|
||||
ret = META_MONITOR_TRANSFORM_180;
|
||||
break;
|
||||
case RR_Rotate_270:
|
||||
ret = WL_OUTPUT_TRANSFORM_270;
|
||||
ret = META_MONITOR_TRANSFORM_270;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -105,42 +107,42 @@ wl_transform_from_xrandr (Rotation rotation)
|
||||
|
||||
#define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270)
|
||||
|
||||
static unsigned int
|
||||
wl_transform_from_xrandr_all (Rotation rotation)
|
||||
static MetaMonitorTransform
|
||||
meta_monitor_transform_from_xrandr_all (Rotation rotation)
|
||||
{
|
||||
unsigned ret;
|
||||
|
||||
/* Handle the common cases first (none or all) */
|
||||
if (rotation == 0 || rotation == RR_Rotate_0)
|
||||
return (1 << WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
return (1 << META_MONITOR_TRANSFORM_NORMAL);
|
||||
|
||||
/* All rotations and one reflection -> all of them by composition */
|
||||
if ((rotation & ALL_ROTATIONS) &&
|
||||
((rotation & RR_Reflect_X) || (rotation & RR_Reflect_Y)))
|
||||
return ALL_WL_TRANSFORMS;
|
||||
return ALL_TRANSFORMS;
|
||||
|
||||
ret = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret = 1 << META_MONITOR_TRANSFORM_NORMAL;
|
||||
if (rotation & RR_Rotate_90)
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_90;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_90;
|
||||
if (rotation & RR_Rotate_180)
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_180;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_180;
|
||||
if (rotation & RR_Rotate_270)
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_270;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_270;
|
||||
if (rotation & (RR_Rotate_0 | RR_Reflect_X))
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED;
|
||||
if (rotation & (RR_Rotate_90 | RR_Reflect_X))
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_90;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED_90;
|
||||
if (rotation & (RR_Rotate_180 | RR_Reflect_X))
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_180;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED_180;
|
||||
if (rotation & (RR_Rotate_270 | RR_Reflect_X))
|
||||
ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_270;
|
||||
ret |= 1 << META_MONITOR_TRANSFORM_FLIPPED_270;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output, const char *propname)
|
||||
{
|
||||
gboolean value;
|
||||
Atom atom, actual_type;
|
||||
@ -148,9 +150,9 @@ output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
unsigned long nitems, bytes_after;
|
||||
unsigned char *buffer;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
|
||||
XRRGetOutputProperty (manager_xrandr->xdisplay,
|
||||
(XID)output->output_id,
|
||||
(XID)output->winsys_id,
|
||||
atom,
|
||||
0, G_MAXLONG, False, False, XA_CARDINAL,
|
||||
&actual_type, &actual_format,
|
||||
@ -166,6 +168,13 @@ output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
return value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return output_get_boolean_property (manager_xrandr, output, "_MUTTER_PRESENTATION_OUTPUT");
|
||||
}
|
||||
|
||||
static int
|
||||
normalize_backlight (MetaOutput *output,
|
||||
int hw_value)
|
||||
@ -186,7 +195,7 @@ output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
|
||||
XRRGetOutputProperty (manager_xrandr->xdisplay,
|
||||
(XID)output->output_id,
|
||||
(XID)output->winsys_id,
|
||||
atom,
|
||||
0, G_MAXLONG, False, False, XA_INTEGER,
|
||||
&actual_type, &actual_format,
|
||||
@ -207,30 +216,34 @@ output_get_backlight_limits_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom atom;
|
||||
XRRPropertyInfo *info;
|
||||
xcb_connection_t *xcb_conn;
|
||||
xcb_randr_query_output_property_reply_t *reply;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
|
||||
info = XRRQueryOutputProperty (manager_xrandr->xdisplay,
|
||||
(XID)output->output_id,
|
||||
atom);
|
||||
|
||||
if (info == NULL)
|
||||
{
|
||||
meta_verbose ("could not get output property for %s\n", output->name);
|
||||
return;
|
||||
}
|
||||
xcb_conn = XGetXCBConnection (manager_xrandr->xdisplay);
|
||||
reply = xcb_randr_query_output_property_reply (xcb_conn,
|
||||
xcb_randr_query_output_property (xcb_conn,
|
||||
(xcb_randr_output_t) output->winsys_id,
|
||||
(xcb_atom_t) atom),
|
||||
NULL);
|
||||
|
||||
if (!info->range || info->num_values != 2)
|
||||
/* This can happen on systems without backlights. */
|
||||
if (reply == NULL)
|
||||
return;
|
||||
|
||||
if (!reply->range || reply->length != 2)
|
||||
{
|
||||
meta_verbose ("backlight %s was not range\n", output->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
output->backlight_min = info->values[0];
|
||||
output->backlight_max = info->values[1];
|
||||
int32_t *values = xcb_randr_query_output_property_valid_values (reply);
|
||||
output->backlight_min = values[0];
|
||||
output->backlight_max = values[1];
|
||||
|
||||
out:
|
||||
XFree (info);
|
||||
free (reply);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -278,25 +291,25 @@ get_edid_property (Display *dpy,
|
||||
|
||||
static GBytes *
|
||||
read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
XID output_id)
|
||||
XID winsys_id)
|
||||
{
|
||||
Atom edid_atom;
|
||||
guint8 *result;
|
||||
gsize len;
|
||||
|
||||
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
edid_atom = XInternAtom (manager_xrandr->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len);
|
||||
result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
|
||||
}
|
||||
|
||||
if (result)
|
||||
@ -312,25 +325,25 @@ read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
|
||||
static gboolean
|
||||
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
XID output_id)
|
||||
MetaOutput *output)
|
||||
{
|
||||
Atom atom;
|
||||
XRRPropertyInfo *info;
|
||||
gboolean result = FALSE;
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "hotplug_mode_update", False);
|
||||
info = XRRQueryOutputProperty (manager_xrandr->xdisplay, output_id,
|
||||
atom);
|
||||
|
||||
if (info)
|
||||
{
|
||||
result = TRUE;
|
||||
XFree (info);
|
||||
}
|
||||
|
||||
return result;
|
||||
return output_get_boolean_property (manager_xrandr, output, "hotplug_mode_update");
|
||||
}
|
||||
|
||||
static char *
|
||||
get_xmode_name (XRRModeInfo *xmode)
|
||||
{
|
||||
int width = xmode->width;
|
||||
int height = xmode->height;
|
||||
|
||||
if (xmode->hSkew != 0)
|
||||
{
|
||||
width += 2 * (xmode->hSkew >> 8);
|
||||
height += 2 * (xmode->hSkew & 0xff);
|
||||
}
|
||||
|
||||
return g_strdup_printf ("%dx%d", width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
@ -417,6 +430,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
mode->height = xmode->height;
|
||||
mode->refresh_rate = (xmode->dotClock /
|
||||
((float)xmode->hTotal * xmode->vTotal));
|
||||
mode->name = get_xmode_name (xmode);
|
||||
}
|
||||
|
||||
for (i = 0; i < (unsigned)resources->ncrtc; i++)
|
||||
@ -434,8 +448,8 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
meta_crtc->rect.width = crtc->width;
|
||||
meta_crtc->rect.height = crtc->height;
|
||||
meta_crtc->is_dirty = FALSE;
|
||||
meta_crtc->transform = wl_transform_from_xrandr (crtc->rotation);
|
||||
meta_crtc->all_transforms = wl_transform_from_xrandr_all (crtc->rotations);
|
||||
meta_crtc->transform = meta_monitor_transform_from_xrandr (crtc->rotation);
|
||||
meta_crtc->all_transforms = meta_monitor_transform_from_xrandr_all (crtc->rotations);
|
||||
|
||||
for (j = 0; j < (unsigned)resources->nmode; j++)
|
||||
{
|
||||
@ -467,10 +481,10 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
GBytes *edid;
|
||||
MonitorInfo *parsed_edid;
|
||||
|
||||
meta_output->output_id = resources->outputs[i];
|
||||
meta_output->winsys_id = resources->outputs[i];
|
||||
meta_output->name = g_strdup (output->name);
|
||||
|
||||
edid = read_output_edid (manager_xrandr, meta_output->output_id);
|
||||
edid = read_output_edid (manager_xrandr, meta_output->winsys_id);
|
||||
if (edid)
|
||||
{
|
||||
gsize len;
|
||||
@ -503,8 +517,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
meta_output->width_mm = output->mm_width;
|
||||
meta_output->height_mm = output->mm_height;
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
meta_output->hotplug_mode_update =
|
||||
output_get_hotplug_mode_update (manager_xrandr, meta_output->output_id);
|
||||
meta_output->hotplug_mode_update = output_get_hotplug_mode_update (manager_xrandr, meta_output);
|
||||
|
||||
meta_output->n_modes = output->nmode;
|
||||
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
|
||||
@ -556,7 +569,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
meta_output->possible_clones[j] = GINT_TO_POINTER (output->clones[j]);
|
||||
}
|
||||
|
||||
meta_output->is_primary = ((XID)meta_output->output_id == primary_output);
|
||||
meta_output->is_primary = ((XID)meta_output->winsys_id == primary_output);
|
||||
meta_output->is_presentation = output_get_presentation_xrandr (manager_xrandr, meta_output);
|
||||
output_get_backlight_limits_xrandr (manager_xrandr, meta_output);
|
||||
|
||||
@ -589,7 +602,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
|
||||
for (k = 0; k < manager->n_outputs; k++)
|
||||
{
|
||||
if (clone == (XID)manager->outputs[k].output_id)
|
||||
if (clone == (XID)manager->outputs[k].winsys_id)
|
||||
{
|
||||
meta_output->possible_clones[j] = &manager->outputs[k];
|
||||
break;
|
||||
@ -605,7 +618,7 @@ meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager,
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
|
||||
|
||||
return read_output_edid (manager_xrandr, output->output_id);
|
||||
return read_output_edid (manager_xrandr, output->winsys_id);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -637,25 +650,25 @@ meta_monitor_manager_xrandr_set_power_save_mode (MetaMonitorManager *manager,
|
||||
}
|
||||
|
||||
static Rotation
|
||||
wl_transform_to_xrandr (enum wl_output_transform transform)
|
||||
meta_monitor_transform_to_xrandr (MetaMonitorTransform transform)
|
||||
{
|
||||
switch (transform)
|
||||
{
|
||||
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||
case META_MONITOR_TRANSFORM_NORMAL:
|
||||
return RR_Rotate_0;
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
case META_MONITOR_TRANSFORM_90:
|
||||
return RR_Rotate_90;
|
||||
case WL_OUTPUT_TRANSFORM_180:
|
||||
case META_MONITOR_TRANSFORM_180:
|
||||
return RR_Rotate_180;
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
case META_MONITOR_TRANSFORM_270:
|
||||
return RR_Rotate_270;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||
case META_MONITOR_TRANSFORM_FLIPPED:
|
||||
return RR_Reflect_X | RR_Rotate_0;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
case META_MONITOR_TRANSFORM_FLIPPED_90:
|
||||
return RR_Reflect_X | RR_Rotate_90;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||
case META_MONITOR_TRANSFORM_FLIPPED_180:
|
||||
return RR_Reflect_X | RR_Rotate_180;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||
case META_MONITOR_TRANSFORM_FLIPPED_270:
|
||||
return RR_Reflect_X | RR_Rotate_270;
|
||||
}
|
||||
|
||||
@ -672,7 +685,7 @@ output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
|
||||
XRRChangeOutputProperty (manager_xrandr->xdisplay,
|
||||
(XID)output->output_id,
|
||||
(XID)output->winsys_id,
|
||||
atom,
|
||||
XA_CARDINAL, 32, PropModeReplace,
|
||||
(unsigned char*) &value, 1);
|
||||
@ -828,7 +841,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
output->crtc = crtc;
|
||||
new_controlled_mask |= 1UL << j;
|
||||
|
||||
outputs[j] = output->output_id;
|
||||
outputs[j] = output->winsys_id;
|
||||
}
|
||||
|
||||
if (crtc->current_mode == mode &&
|
||||
@ -847,7 +860,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
manager_xrandr->time,
|
||||
crtc_info->x, crtc_info->y,
|
||||
(XID)mode->mode_id,
|
||||
wl_transform_to_xrandr (crtc_info->transform),
|
||||
meta_monitor_transform_to_xrandr (crtc_info->transform),
|
||||
outputs, n_outputs);
|
||||
|
||||
if (ok != Success)
|
||||
@ -891,7 +904,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
{
|
||||
XRRSetOutputPrimary (manager_xrandr->xdisplay,
|
||||
DefaultRootWindow (manager_xrandr->xdisplay),
|
||||
(XID)output_info->output->output_id);
|
||||
(XID)output_info->output->winsys_id);
|
||||
}
|
||||
|
||||
output_set_presentation_xrandr (manager_xrandr,
|
||||
@ -934,7 +947,7 @@ meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager,
|
||||
|
||||
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
|
||||
XRRChangeOutputProperty (manager_xrandr->xdisplay,
|
||||
(XID)output->output_id,
|
||||
(XID)output->winsys_id,
|
||||
atom,
|
||||
XA_INTEGER, 32, PropModeReplace,
|
||||
(unsigned char *) &hw_value, 1);
|
||||
|
@ -51,6 +51,12 @@ round_to_fixed (float x)
|
||||
return roundf (x * 256);
|
||||
}
|
||||
|
||||
/* Help macros to scale from OpenGL <-1,1> coordinates system to
|
||||
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
|
||||
*/
|
||||
#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
||||
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
||||
|
||||
/* This helper function checks if (according to our fixed point precision)
|
||||
* the vertices @verts form a box of width @widthf and height @heightf
|
||||
* located at integral coordinates. These coordinates are returned
|
||||
@ -118,3 +124,67 @@ meta_actor_is_untransformed (ClutterActor *actor,
|
||||
return meta_actor_vertices_are_untransformed (verts, widthf, heightf, x_origin, y_origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_actor_painting_untransformed:
|
||||
* @paint_width: the width of the painted area
|
||||
* @paint_height: the height of the painted area
|
||||
* @x_origin: if the transform is only an integer translation
|
||||
* then the X coordinate of the location of the origin under the transformation
|
||||
* from drawing space to screen pixel space is returned here.
|
||||
* @y_origin: if the transform is only an integer translation
|
||||
* then the X coordinate of the location of the origin under the transformation
|
||||
* from drawing space to screen pixel space is returned here.
|
||||
*
|
||||
* Determines if the current painting transform is an integer translation.
|
||||
* This can differ from the result of meta_actor_is_untransformed() when
|
||||
* painting an actor if we're inside a inside a clone paint. @paint_width
|
||||
* and @paint_height are used to determine the vertices of the rectangle
|
||||
* we check to see if the painted area is "close enough" to the integer
|
||||
* transform.
|
||||
*/
|
||||
gboolean
|
||||
meta_actor_painting_untransformed (int paint_width,
|
||||
int paint_height,
|
||||
int *x_origin,
|
||||
int *y_origin)
|
||||
{
|
||||
CoglMatrix modelview, projection, modelview_projection;
|
||||
ClutterVertex vertices[4];
|
||||
float viewport[4];
|
||||
int i;
|
||||
|
||||
cogl_get_modelview_matrix (&modelview);
|
||||
cogl_get_projection_matrix (&projection);
|
||||
|
||||
cogl_matrix_multiply (&modelview_projection,
|
||||
&projection,
|
||||
&modelview);
|
||||
|
||||
vertices[0].x = 0;
|
||||
vertices[0].y = 0;
|
||||
vertices[0].z = 0;
|
||||
vertices[1].x = paint_width;
|
||||
vertices[1].y = 0;
|
||||
vertices[1].z = 0;
|
||||
vertices[2].x = 0;
|
||||
vertices[2].y = paint_height;
|
||||
vertices[2].z = 0;
|
||||
vertices[3].x = paint_width;
|
||||
vertices[3].y = paint_height;
|
||||
vertices[3].z = 0;
|
||||
|
||||
cogl_get_viewport (viewport);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
float w = 1;
|
||||
cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w);
|
||||
vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w,
|
||||
viewport[2], viewport[0]);
|
||||
vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w,
|
||||
viewport[3], viewport[1]);
|
||||
}
|
||||
|
||||
return meta_actor_vertices_are_untransformed (vertices, paint_width, paint_height, x_origin, y_origin);
|
||||
}
|
||||
|
||||
|
@ -31,4 +31,9 @@ gboolean meta_actor_is_untransformed (ClutterActor *actor,
|
||||
int *x_origin,
|
||||
int *y_origin);
|
||||
|
||||
gboolean meta_actor_painting_untransformed (int paint_width,
|
||||
int paint_height,
|
||||
int *x_origin,
|
||||
int *y_origin);
|
||||
|
||||
#endif /* __META_CLUTTER_UTILS_H__ */
|
||||
|
@ -22,48 +22,6 @@
|
||||
#include <clutter/clutter.h>
|
||||
#include "cogl-utils.h"
|
||||
|
||||
/**
|
||||
* meta_create_color_texture_4ub:
|
||||
* @red: red component
|
||||
* @green: green component
|
||||
* @blue: blue component
|
||||
* @alpha: alpha component
|
||||
* @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE;
|
||||
* %COGL_TEXTURE_NO_SLICING is useful if the texture will be
|
||||
* repeated to create a constant color fill, since hardware
|
||||
* repeat can't be used for a sliced texture.
|
||||
*
|
||||
* Creates a texture that is a single pixel with the specified
|
||||
* unpremultiplied color components.
|
||||
*
|
||||
* Return value: (transfer full): a newly created Cogl texture
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_create_color_texture_4ub (guint8 red,
|
||||
guint8 green,
|
||||
guint8 blue,
|
||||
guint8 alpha,
|
||||
CoglTextureFlags flags)
|
||||
{
|
||||
CoglColor color;
|
||||
guint8 pixel[4];
|
||||
|
||||
cogl_color_init_from_4ub (&color, red, green, blue, alpha);
|
||||
cogl_color_premultiply (&color);
|
||||
|
||||
pixel[0] = cogl_color_get_red_byte (&color);
|
||||
pixel[1] = cogl_color_get_green_byte (&color);
|
||||
pixel[2] = cogl_color_get_blue_byte (&color);
|
||||
pixel[3] = cogl_color_get_alpha_byte (&color);
|
||||
|
||||
return cogl_texture_new_from_data (1, 1,
|
||||
flags,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
4, pixel);
|
||||
}
|
||||
|
||||
|
||||
/* Based on gnome-shell/src/st/st-private.c:_st_create_texture_material.c */
|
||||
|
||||
/**
|
||||
@ -106,3 +64,78 @@ meta_create_texture_pipeline (CoglTexture *src_texture)
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static gboolean is_pot(int x)
|
||||
{
|
||||
return x > 0 && (x & (x - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_create_texture:
|
||||
* @width: width of the texture to create
|
||||
* @height: height of the texture to create
|
||||
* @components; components to store in the texture (color or alpha)
|
||||
* @flags: flags that affect the allocation behavior
|
||||
*
|
||||
* Creates a texture of the given size with the specified components
|
||||
* for use as a frame buffer object.
|
||||
*
|
||||
* If non-power-of-two textures are not supported on the system, then
|
||||
* the texture will be created as a texture rectangle; in this case,
|
||||
* hardware repeating isn't possible, and texture coordinates are also
|
||||
* different, but Cogl hides these issues from the application, except from
|
||||
* GLSL shaders. Since GLSL is never (or at least almost never)
|
||||
* present on such a system, this is not typically an issue.
|
||||
*
|
||||
* If %META_TEXTURE_ALLOW_SLICING is present in @flags, and the texture
|
||||
* is larger than the texture size limits of the system, then the texture
|
||||
* will be created as a sliced texture. This also will cause problems
|
||||
* with using the texture with GLSL, and is more likely to be an issue
|
||||
* since all GL implementations have texture size limits, and they can
|
||||
* be as small as 2048x2048 on reasonably current systems.
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_create_texture (int width,
|
||||
int height,
|
||||
CoglTextureComponents components,
|
||||
MetaTextureFlags flags)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||
CoglTexture *texture;
|
||||
|
||||
gboolean should_use_rectangle = FALSE;
|
||||
|
||||
if (!(is_pot (width) && is_pot (height)) &&
|
||||
!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT))
|
||||
{
|
||||
if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
|
||||
should_use_rectangle = TRUE;
|
||||
else
|
||||
g_error ("Cannot create texture. Support for GL_ARB_texture_non_power_of_two or "
|
||||
"ARB_texture_rectangle is required");
|
||||
}
|
||||
|
||||
if (should_use_rectangle)
|
||||
texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (ctx, width, height));
|
||||
else
|
||||
texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height));
|
||||
cogl_texture_set_components (texture, components);
|
||||
|
||||
if ((flags & META_TEXTURE_ALLOW_SLICING) != 0)
|
||||
{
|
||||
/* To find out if we need to slice the texture, we have to go ahead and force storage
|
||||
* to be allocated
|
||||
*/
|
||||
CoglError *catch_error = NULL;
|
||||
if (!cogl_texture_allocate (texture, &catch_error))
|
||||
{
|
||||
cogl_error_free (catch_error);
|
||||
cogl_object_unref (texture);
|
||||
texture = COGL_TEXTURE (cogl_texture_2d_sliced_new_with_size (ctx, width, height, COGL_TEXTURE_MAX_WASTE));
|
||||
cogl_texture_set_components (texture, components);
|
||||
}
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
@ -23,11 +23,16 @@
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
CoglTexture * meta_create_color_texture_4ub (guint8 red,
|
||||
guint8 green,
|
||||
guint8 blue,
|
||||
guint8 alpha,
|
||||
CoglTextureFlags flags);
|
||||
CoglPipeline * meta_create_texture_pipeline (CoglTexture *texture);
|
||||
|
||||
typedef enum {
|
||||
META_TEXTURE_FLAGS_NONE = 0,
|
||||
META_TEXTURE_ALLOW_SLICING = 1 << 1
|
||||
} MetaTextureFlags;
|
||||
|
||||
CoglTexture *meta_create_texture (int width,
|
||||
int height,
|
||||
CoglTextureComponents components,
|
||||
MetaTextureFlags flags);
|
||||
|
||||
#endif /* __META_COGL_UTILS_H__ */
|
||||
|
@ -38,6 +38,8 @@ struct _MetaCompositor
|
||||
gint switch_workspace_in_progress;
|
||||
|
||||
MetaPluginManager *plugin_mgr;
|
||||
|
||||
gboolean frame_has_updated_xsurfaces;
|
||||
};
|
||||
|
||||
/* Wait 2ms after vblank before starting to draw next frame */
|
||||
|
@ -67,40 +67,29 @@
|
||||
#include <meta/compositor-mutter.h>
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-backend.h>
|
||||
#include <meta/meta-background-actor.h>
|
||||
#include <meta/meta-background-group.h>
|
||||
#include <meta/meta-shadow-factory.h>
|
||||
#include "meta-window-actor-private.h"
|
||||
#include "meta-window-group.h"
|
||||
#include "meta-stage.h"
|
||||
#include "window-private.h" /* to check window->hidden */
|
||||
#include "display-private.h" /* for meta_display_lookup_x_window() */
|
||||
#include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
|
||||
#include "util-private.h"
|
||||
#include "frame.h"
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#include "backends/meta-backend.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
is_modal (MetaDisplay *display)
|
||||
{
|
||||
return display->grab_op == META_GRAB_OP_COMPOSITOR;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
composite_at_least_version (MetaDisplay *display, int maj, int min)
|
||||
{
|
||||
static int major = -1;
|
||||
static int minor = -1;
|
||||
|
||||
if (major == -1)
|
||||
meta_display_get_compositor_version (display, &major, &minor);
|
||||
|
||||
return (major > maj || (major == maj && minor >= min));
|
||||
return display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB;
|
||||
}
|
||||
|
||||
static void sync_actor_stacking (MetaCompositor *compositor);
|
||||
@ -146,33 +135,8 @@ process_damage (MetaCompositor *compositor,
|
||||
{
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
meta_window_actor_process_x11_damage (window_actor, event);
|
||||
}
|
||||
|
||||
static Window
|
||||
get_output_window (MetaCompositor *compositor)
|
||||
{
|
||||
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
||||
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
|
||||
Window output;
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
output = XCompositeGetOverlayWindow (xdisplay, DefaultRootWindow (xdisplay));
|
||||
|
||||
meta_core_add_old_event_mask (xdisplay, output, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XISelectEvents (xdisplay, output, &mask, 1);
|
||||
|
||||
return output;
|
||||
compositor->frame_has_updated_xsurfaces = TRUE;
|
||||
}
|
||||
|
||||
/* compat helper */
|
||||
@ -381,12 +345,20 @@ meta_begin_modal_for_plugin (MetaCompositor *compositor,
|
||||
return FALSE;
|
||||
|
||||
display->grab_op = META_GRAB_OP_COMPOSITOR;
|
||||
display->event_route = META_EVENT_ROUTE_COMPOSITOR_GRAB;
|
||||
display->grab_window = NULL;
|
||||
display->grab_have_pointer = TRUE;
|
||||
display->grab_have_keyboard = TRUE;
|
||||
|
||||
g_signal_emit_by_name (display, "grab-op-begin",
|
||||
meta_plugin_get_screen (plugin),
|
||||
display->grab_window, display->grab_op);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_display_sync_wayland_input_focus (display);
|
||||
{
|
||||
meta_display_sync_wayland_input_focus (display);
|
||||
meta_display_cancel_touch (display);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -401,7 +373,12 @@ meta_end_modal_for_plugin (MetaCompositor *compositor,
|
||||
|
||||
g_return_if_fail (is_modal (display));
|
||||
|
||||
g_signal_emit_by_name (display, "grab-op-end",
|
||||
meta_plugin_get_screen (plugin),
|
||||
display->grab_window, display->grab_op);
|
||||
|
||||
display->grab_op = META_GRAB_OP_NONE;
|
||||
display->event_route = META_EVENT_ROUTE_NORMAL;
|
||||
display->grab_window = NULL;
|
||||
display->grab_have_pointer = FALSE;
|
||||
display->grab_have_keyboard = FALSE;
|
||||
@ -423,8 +400,10 @@ after_stage_paint (ClutterStage *stage,
|
||||
for (l = compositor->windows; l; l = l->next)
|
||||
meta_window_actor_post_paint (l->data);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -476,62 +455,24 @@ meta_compositor_manage (MetaCompositor *compositor)
|
||||
MetaDisplay *display = compositor->display;
|
||||
Display *xdisplay = display->xdisplay;
|
||||
MetaScreen *screen = display->screen;
|
||||
Window xwin = 0;
|
||||
gint width, height;
|
||||
|
||||
meta_screen_set_cm_selection (display->screen);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaWaylandCompositor *wayland_compositor = meta_wayland_compositor_get_default ();
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
compositor->stage = meta_backend_get_stage (backend);
|
||||
}
|
||||
|
||||
compositor->stage = meta_stage_new ();
|
||||
clutter_actor_show (compositor->stage);
|
||||
|
||||
wayland_compositor->stage = compositor->stage;
|
||||
|
||||
meta_screen_get_size (screen, &width, &height);
|
||||
clutter_actor_set_size (compositor->stage, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
compositor->stage = clutter_stage_new ();
|
||||
|
||||
meta_screen_get_size (screen, &width, &height);
|
||||
clutter_actor_realize (compositor->stage);
|
||||
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
|
||||
{
|
||||
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
||||
Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend);
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
meta_core_add_old_event_mask (backend_xdisplay, xwin, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XIClearMask (mask.mask, XI_TouchBegin);
|
||||
XIClearMask (mask.mask, XI_TouchEnd);
|
||||
XIClearMask (mask.mask, XI_TouchUpdate);
|
||||
XISelectEvents (backend_xdisplay, xwin, &mask, 1);
|
||||
}
|
||||
}
|
||||
|
||||
clutter_stage_set_paint_callback (CLUTTER_STAGE (compositor->stage),
|
||||
after_stage_paint,
|
||||
compositor,
|
||||
NULL);
|
||||
/* We use connect_after() here to accomodate code in GNOME Shell that,
|
||||
* when benchmarking drawing performance, connects to ::after-paint
|
||||
* and calls glFinish(). The timing information from that will be
|
||||
* more accurate if we hold off until that completes before we signal
|
||||
* apps to begin drawing the next frame. If there are no other
|
||||
* connections to ::after-paint, connect() vs. connect_after() doesn't
|
||||
* matter.
|
||||
*/
|
||||
g_signal_connect_after (CLUTTER_STAGE (compositor->stage), "after-paint",
|
||||
G_CALLBACK (after_stage_paint), compositor);
|
||||
|
||||
clutter_stage_set_sync_delay (CLUTTER_STAGE (compositor->stage), META_SYNC_DELAY);
|
||||
|
||||
@ -550,7 +491,12 @@ meta_compositor_manage (MetaCompositor *compositor)
|
||||
}
|
||||
else
|
||||
{
|
||||
compositor->output = get_output_window (compositor);
|
||||
Window xwin;
|
||||
|
||||
compositor->output = screen->composite_overlay_window;
|
||||
|
||||
xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (meta_get_backend ()));
|
||||
|
||||
XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
|
||||
|
||||
meta_empty_stage_input_region (screen);
|
||||
@ -755,9 +701,6 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
XEvent *event,
|
||||
MetaWindow *window)
|
||||
{
|
||||
if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
|
||||
return TRUE;
|
||||
|
||||
if (!meta_is_wayland_compositor () &&
|
||||
event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
{
|
||||
@ -977,7 +920,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
old_actor = old_stack->data;
|
||||
old_window = meta_window_actor_get_meta_window (old_actor);
|
||||
|
||||
if (old_window->hidden &&
|
||||
if ((old_window->hidden || old_window->unmanaging) &&
|
||||
!meta_window_actor_effect_in_progress (old_actor))
|
||||
{
|
||||
old_stack = g_list_delete_link (old_stack, old_stack);
|
||||
@ -1011,7 +954,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
* filtered out non-animating hidden windows above.
|
||||
*/
|
||||
if (old_actor &&
|
||||
(!stack_actor || old_window->hidden))
|
||||
(!stack_actor || old_window->hidden || old_window->unmanaging))
|
||||
{
|
||||
actor = old_actor;
|
||||
window = old_window;
|
||||
@ -1045,43 +988,6 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor,
|
||||
meta_window_actor_sync_actor_geometry (window_actor, did_placement);
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_sync_screen_size (MetaCompositor *compositor,
|
||||
guint width,
|
||||
guint height)
|
||||
{
|
||||
MetaDisplay *display = compositor->display;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* FIXME: when we support a sliced stage, this is the place to do it
|
||||
But! This is not the place to apply KMS config, here we only
|
||||
notify Clutter/Cogl/GL that the framebuffer sizes changed.
|
||||
|
||||
And because for now clutter does not do sliced, we use one
|
||||
framebuffer the size of the whole screen, and when running on
|
||||
bare metal MetaMonitorManager will do the necessary tricks to
|
||||
show the right portions on the right screens.
|
||||
*/
|
||||
|
||||
clutter_actor_set_size (compositor->stage, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
Display *xdisplay;
|
||||
Window xwin;
|
||||
|
||||
xdisplay = meta_display_get_xdisplay (display);
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
}
|
||||
|
||||
meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
|
||||
meta_screen_get_screen_number (display->screen),
|
||||
width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
frame_callback (CoglOnscreen *onscreen,
|
||||
CoglFrameEvent event,
|
||||
@ -1152,6 +1058,33 @@ pre_paint_windows (MetaCompositor *compositor)
|
||||
|
||||
for (l = compositor->windows; l; l = l->next)
|
||||
meta_window_actor_pre_paint (l->data);
|
||||
|
||||
if (compositor->frame_has_updated_xsurfaces)
|
||||
{
|
||||
/* We need to make sure that any X drawing that happens before
|
||||
* the XDamageSubtract() for each window above is visible to
|
||||
* subsequent GL rendering; the only standardized way to do this
|
||||
* is EXT_x11_sync_object, which isn't yet widely available. For
|
||||
* now, we count on details of Xorg and the open source drivers,
|
||||
* and hope for the best otherwise.
|
||||
*
|
||||
* Xorg and open source driver specifics:
|
||||
*
|
||||
* The X server makes sure to flush drawing to the kernel before
|
||||
* sending out damage events, but since we use
|
||||
* DamageReportBoundingBox there may be drawing between the last
|
||||
* damage event and the XDamageSubtract() that needs to be
|
||||
* flushed as well.
|
||||
*
|
||||
* Xorg always makes sure that drawing is flushed to the kernel
|
||||
* before writing events or responses to the client, so any
|
||||
* round trip request at this point is sufficient to flush the
|
||||
* GLX buffers.
|
||||
*/
|
||||
XSync (compositor->display->xdisplay, False);
|
||||
|
||||
compositor->frame_has_updated_xsurfaces = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -1182,11 +1115,7 @@ meta_compositor_new (MetaDisplay *display)
|
||||
{
|
||||
MetaCompositor *compositor;
|
||||
|
||||
if (!composite_at_least_version (display, 0, 3))
|
||||
return NULL;
|
||||
|
||||
compositor = g_new0 (MetaCompositor, 1);
|
||||
|
||||
compositor->display = display;
|
||||
|
||||
if (g_getenv("META_DISABLE_MIPMAPS"))
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright 2009 Sander Dijkhuis
|
||||
* Copyright 2010 Red Hat, Inc.
|
||||
* Copyright 2014 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
|
||||
@ -26,23 +26,122 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
/*
|
||||
* The overall model drawing model of this widget is that we have one
|
||||
* texture, or two interpolated textures, possibly with alpha or
|
||||
* margins that let the underlying background show through, blended
|
||||
* over a solid color or a gradient. The result of that combination
|
||||
* can then be affected by a "vignette" that darkens the background
|
||||
* away from a central point (or as a no-GLSL fallback, simply darkens
|
||||
* the background) and by overall opacity.
|
||||
*
|
||||
* As of GNOME 3.14, GNOME is only using a fraction of this when the
|
||||
* user sets the background through the control center - what can be
|
||||
* set is:
|
||||
*
|
||||
* A single image without a border
|
||||
* An animation of images without a border that blend together,
|
||||
* with the blend changing every 4-5 minutes
|
||||
* A solid color with a repeated noise texture blended over it
|
||||
*
|
||||
* This all is pretty easy to do in a fragment shader, except when:
|
||||
*
|
||||
* A) We don't have GLSL - in this case, the operation of
|
||||
* interpolating the two textures and blending the result over the
|
||||
* background can't be expressed with Cogl's fixed-function layer
|
||||
* combining (which is confined to what GL's texture environment
|
||||
* combining can do) So we can only handle the above directly if
|
||||
* there are no margins or alpha.
|
||||
*
|
||||
* B) The image textures are sliced. Texture size limits on older
|
||||
* hardware (pre-965 intel hardware, r300, etc.) is often 2048,
|
||||
* and it would be common to use a texture larger than this for a
|
||||
* background and expect it to be scaled down. Cogl can compensate
|
||||
* for this by breaking the texture up into multiple textures, but
|
||||
* can't multitexture with sliced textures. So we can only handle
|
||||
* the above if there's a single texture.
|
||||
*
|
||||
* However, even when we *can* represent everything in a single pass,
|
||||
* it's not necessarily efficient. If we want to draw a 1024x768
|
||||
* background, it's pretty inefficient to bilinearly texture from
|
||||
* two 2560x1440 images and mix that. So the drawing model we take
|
||||
* here is that MetaBackground generates a single texture (which
|
||||
* might be a 1x1 texture for a solid color, or a 1x2 texture for a
|
||||
* gradient, or a repeated texture for wallpaper, or a pre-rendered
|
||||
* texture the size of the screen), and we draw with that, possibly
|
||||
* adding the vignette and opacity.
|
||||
*/
|
||||
|
||||
#include <cogl/cogl-texture-pixmap-x11.h>
|
||||
#include <config.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "cogl-utils.h"
|
||||
#include "compositor-private.h"
|
||||
#include "clutter-utils.h"
|
||||
#include <meta/errors.h>
|
||||
#include <meta/meta-background.h>
|
||||
#include "meta-background-actor-private.h"
|
||||
#include "meta-background-private.h"
|
||||
#include "meta-cullable.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_META_SCREEN = 1,
|
||||
PROP_MONITOR,
|
||||
PROP_BACKGROUND,
|
||||
PROP_VIGNETTE,
|
||||
PROP_VIGNETTE_SHARPNESS,
|
||||
PROP_BRIGHTNESS
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CHANGED_BACKGROUND = 1 << 0,
|
||||
CHANGED_EFFECTS = 1 << 2,
|
||||
CHANGED_VIGNETTE_PARAMETERS = 1 << 3,
|
||||
CHANGED_ALL = 0xFFFF
|
||||
} ChangedFlags;
|
||||
|
||||
#define VERTEX_SHADER_DECLARATIONS \
|
||||
"uniform vec2 scale;\n" \
|
||||
"uniform vec2 offset;\n" \
|
||||
"varying vec2 position;\n" \
|
||||
|
||||
#define VERTEX_SHADER_CODE \
|
||||
"position = cogl_tex_coord0_in.xy * scale + offset;\n" \
|
||||
|
||||
#define FRAGMENT_SHADER_DECLARATIONS \
|
||||
"uniform float vignette_sharpness;\n" \
|
||||
"varying vec2 position;\n" \
|
||||
|
||||
#define FRAGMENT_SHADER_CODE \
|
||||
"float t = 2.0 * length(position);\n" \
|
||||
"t = min(t, 1.0);\n" \
|
||||
"float pixel_brightness = 1 - t * vignette_sharpness;\n" \
|
||||
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
|
||||
|
||||
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
|
||||
|
||||
typedef enum {
|
||||
PIPELINE_VIGNETTE = (1 << 0),
|
||||
PIPELINE_BLEND = (1 << 1),
|
||||
} PipelineFlags;
|
||||
|
||||
struct _MetaBackgroundActorPrivate
|
||||
{
|
||||
MetaScreen *screen;
|
||||
int monitor;
|
||||
|
||||
MetaBackground *background;
|
||||
|
||||
gboolean vignette;
|
||||
double brightness;
|
||||
double vignette_sharpness;
|
||||
|
||||
ChangedFlags changed;
|
||||
CoglPipeline *pipeline;
|
||||
PipelineFlags pipeline_flags;
|
||||
cairo_rectangle_int_t texture_area;
|
||||
gboolean force_bilinear;
|
||||
|
||||
cairo_region_t *clip_region;
|
||||
};
|
||||
|
||||
@ -66,27 +165,45 @@ static void
|
||||
meta_background_actor_dispose (GObject *object)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
|
||||
set_clip_region (self, NULL);
|
||||
meta_background_actor_set_background (self, NULL);
|
||||
if (priv->pipeline)
|
||||
{
|
||||
cogl_object_unref (priv->pipeline);
|
||||
priv->pipeline = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
get_preferred_size (MetaBackgroundActor *self,
|
||||
gfloat *width,
|
||||
gfloat *height)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = META_BACKGROUND_ACTOR (self)->priv;
|
||||
MetaRectangle monitor_geometry;
|
||||
|
||||
meta_screen_get_monitor_geometry (priv->screen, priv->monitor, &monitor_geometry);
|
||||
|
||||
if (width != NULL)
|
||||
*width = monitor_geometry.width;
|
||||
|
||||
if (height != NULL)
|
||||
*height = monitor_geometry.height;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_get_preferred_width (ClutterActor *actor,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
ClutterContent *content;
|
||||
gfloat width;
|
||||
|
||||
content = clutter_actor_get_content (actor);
|
||||
|
||||
if (content)
|
||||
clutter_content_get_preferred_size (content, &width, NULL);
|
||||
else
|
||||
width = 0;
|
||||
get_preferred_size (META_BACKGROUND_ACTOR (actor), &width, NULL);
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p = width;
|
||||
@ -101,15 +218,9 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
|
||||
gfloat *natural_height_p)
|
||||
|
||||
{
|
||||
ClutterContent *content;
|
||||
gfloat height;
|
||||
|
||||
content = clutter_actor_get_content (actor);
|
||||
|
||||
if (content)
|
||||
clutter_content_get_preferred_size (content, NULL, &height);
|
||||
else
|
||||
height = 0;
|
||||
get_preferred_size (META_BACKGROUND_ACTOR (actor), NULL, &height);
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p = height;
|
||||
@ -117,43 +228,430 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
|
||||
*natural_height_p = height;
|
||||
}
|
||||
|
||||
static CoglPipeline *
|
||||
make_pipeline (PipelineFlags pipeline_flags)
|
||||
{
|
||||
static CoglPipeline *templates[4];
|
||||
CoglPipeline **templatep;
|
||||
|
||||
templatep = &templates[pipeline_flags];
|
||||
if (*templatep == NULL)
|
||||
{
|
||||
/* Cogl automatically caches pipelines with no eviction policy,
|
||||
* so we need to prevent identical pipelines from getting cached
|
||||
* separately, by reusing the same shader snippets.
|
||||
*/
|
||||
*templatep = COGL_PIPELINE (meta_create_texture_pipeline (NULL));
|
||||
|
||||
if ((pipeline_flags & PIPELINE_VIGNETTE) != 0)
|
||||
{
|
||||
static CoglSnippet *vertex_snippet;
|
||||
static CoglSnippet *fragment_snippet;
|
||||
|
||||
if (!vertex_snippet)
|
||||
vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
|
||||
VERTEX_SHADER_DECLARATIONS, VERTEX_SHADER_CODE);
|
||||
|
||||
cogl_pipeline_add_snippet (*templatep, vertex_snippet);
|
||||
|
||||
if (!fragment_snippet)
|
||||
fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
|
||||
FRAGMENT_SHADER_DECLARATIONS, FRAGMENT_SHADER_CODE);
|
||||
|
||||
cogl_pipeline_add_snippet (*templatep, fragment_snippet);
|
||||
}
|
||||
|
||||
if ((pipeline_flags & PIPELINE_BLEND) == 0)
|
||||
cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL);
|
||||
}
|
||||
|
||||
return cogl_pipeline_copy (*templatep);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_pipeline (MetaBackgroundActor *self,
|
||||
cairo_rectangle_int_t *actor_pixel_rect)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
PipelineFlags pipeline_flags = 0;
|
||||
guint8 opacity;
|
||||
float color_component;
|
||||
CoglPipelineFilter filter;
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
|
||||
if (opacity < 255)
|
||||
pipeline_flags |= PIPELINE_BLEND;
|
||||
if (priv->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
||||
pipeline_flags |= PIPELINE_VIGNETTE;
|
||||
|
||||
if (priv->pipeline &&
|
||||
pipeline_flags != priv->pipeline_flags)
|
||||
{
|
||||
cogl_object_unref (priv->pipeline);
|
||||
priv->pipeline = NULL;
|
||||
}
|
||||
|
||||
if (priv->pipeline == NULL)
|
||||
{
|
||||
priv->pipeline_flags = pipeline_flags;
|
||||
priv->pipeline = make_pipeline (pipeline_flags);
|
||||
priv->changed = CHANGED_ALL;
|
||||
}
|
||||
|
||||
if ((priv->changed & CHANGED_BACKGROUND) != 0)
|
||||
{
|
||||
CoglPipelineWrapMode wrap_mode;
|
||||
CoglTexture *texture = meta_background_get_texture (priv->background,
|
||||
priv->monitor,
|
||||
&priv->texture_area,
|
||||
&wrap_mode);
|
||||
priv->force_bilinear = texture &&
|
||||
(priv->texture_area.width != (int)cogl_texture_get_width (texture) ||
|
||||
priv->texture_area.height != (int)cogl_texture_get_height (texture));
|
||||
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
|
||||
cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, wrap_mode);
|
||||
}
|
||||
|
||||
if ((priv->changed & CHANGED_VIGNETTE_PARAMETERS) != 0)
|
||||
{
|
||||
cogl_pipeline_set_uniform_1f (priv->pipeline,
|
||||
cogl_pipeline_get_uniform_location (priv->pipeline,
|
||||
"vignette_sharpness"),
|
||||
priv->vignette_sharpness);
|
||||
}
|
||||
|
||||
if (priv->vignette)
|
||||
{
|
||||
color_component = priv->brightness * opacity / 255.;
|
||||
|
||||
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
||||
{
|
||||
/* Darken everything to match the average brightness that would
|
||||
* be there if we were drawing the vignette, which is
|
||||
* (1 - (pi/12.) * vignette_sharpness) [exercise for the reader :]
|
||||
*/
|
||||
color_component *= (1 - 0.74 * priv->vignette_sharpness);
|
||||
}
|
||||
}
|
||||
else
|
||||
color_component = opacity / 255.;
|
||||
|
||||
cogl_pipeline_set_color4f (priv->pipeline,
|
||||
color_component,
|
||||
color_component,
|
||||
color_component,
|
||||
opacity / 255.);
|
||||
|
||||
if (!priv->force_bilinear &&
|
||||
meta_actor_painting_untransformed (actor_pixel_rect->width, actor_pixel_rect->height, NULL, NULL))
|
||||
filter = COGL_PIPELINE_FILTER_NEAREST;
|
||||
else
|
||||
filter = COGL_PIPELINE_FILTER_LINEAR;
|
||||
|
||||
cogl_pipeline_set_layer_filters (priv->pipeline, 0, filter, filter);
|
||||
}
|
||||
|
||||
static void
|
||||
set_glsl_parameters (MetaBackgroundActor *self,
|
||||
cairo_rectangle_int_t *actor_pixel_rect)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
float scale[2];
|
||||
float offset[2];
|
||||
|
||||
/* Compute a scale and offset for transforming texture coordinates to the
|
||||
* coordinate system from [-0.5 to 0.5] across the area of the actor
|
||||
*/
|
||||
scale[0] = priv->texture_area.width / (float)actor_pixel_rect->width;
|
||||
scale[1] = priv->texture_area.height / (float)actor_pixel_rect->height;
|
||||
offset[0] = priv->texture_area.x / (float)actor_pixel_rect->width - 0.5;
|
||||
offset[1] = priv->texture_area.y / (float)actor_pixel_rect->height - 0.5;
|
||||
|
||||
cogl_pipeline_set_uniform_float (priv->pipeline,
|
||||
cogl_pipeline_get_uniform_location (priv->pipeline,
|
||||
"scale"),
|
||||
2, 1, scale);
|
||||
|
||||
cogl_pipeline_set_uniform_float (priv->pipeline,
|
||||
cogl_pipeline_get_uniform_location (priv->pipeline,
|
||||
"offset"),
|
||||
2, 1, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||
CoglPipeline *pipeline,
|
||||
cairo_rectangle_int_t *rect,
|
||||
cairo_rectangle_int_t *texture_area)
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
float tx1, ty1, tx2, ty2;
|
||||
|
||||
x1 = rect->x;
|
||||
y1 = rect->y;
|
||||
x2 = rect->x + rect->width;
|
||||
y2 = rect->y + rect->height;
|
||||
|
||||
tx1 = (x1 - texture_area->x) / texture_area->width;
|
||||
ty1 = (y1 - texture_area->y) / texture_area->height;
|
||||
tx2 = (x2 - texture_area->x) / texture_area->width;
|
||||
ty2 = (y2 - texture_area->y) / texture_area->height;
|
||||
|
||||
cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
|
||||
x1, y1, x2, y2,
|
||||
tx1, ty1, tx2, ty2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_background_actor_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
return clutter_paint_volume_set_from_allocation (volume, actor);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
ClutterActorBox actor_box;
|
||||
cairo_rectangle_int_t actor_pixel_rect;
|
||||
CoglFramebuffer *fb;
|
||||
int i;
|
||||
|
||||
if ((priv->clip_region && cairo_region_is_empty (priv->clip_region)))
|
||||
return;
|
||||
|
||||
clutter_actor_get_content_box (actor, &actor_box);
|
||||
actor_pixel_rect.x = actor_box.x1;
|
||||
actor_pixel_rect.y = actor_box.y1;
|
||||
actor_pixel_rect.width = actor_box.x2 - actor_box.x1;
|
||||
actor_pixel_rect.height = actor_box.y2 - actor_box.y1;
|
||||
|
||||
setup_pipeline (self, &actor_pixel_rect);
|
||||
set_glsl_parameters (self, &actor_pixel_rect);
|
||||
|
||||
/* Limit to how many separate rectangles we'll draw; beyond this just
|
||||
* fall back and draw the whole thing */
|
||||
#define MAX_RECTS 64
|
||||
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
/* Now figure out what to actually paint.
|
||||
*/
|
||||
if (priv->clip_region != NULL)
|
||||
{
|
||||
int n_rects = cairo_region_num_rectangles (priv->clip_region);
|
||||
if (n_rects <= MAX_RECTS)
|
||||
{
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_region_get_rectangle (priv->clip_region, i, &rect);
|
||||
|
||||
if (!gdk_rectangle_intersect (&actor_pixel_rect, &rect, &rect))
|
||||
continue;
|
||||
|
||||
paint_clipped_rectangle (fb, priv->pipeline, &rect, &priv->texture_area);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
paint_clipped_rectangle (fb, priv->pipeline, &actor_pixel_rect, &priv->texture_area);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_META_SCREEN:
|
||||
priv->screen = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_MONITOR:
|
||||
priv->monitor = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_BACKGROUND:
|
||||
meta_background_actor_set_background (self, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_VIGNETTE:
|
||||
meta_background_actor_set_vignette (self,
|
||||
g_value_get_boolean (value),
|
||||
priv->brightness,
|
||||
priv->vignette_sharpness);
|
||||
break;
|
||||
case PROP_VIGNETTE_SHARPNESS:
|
||||
meta_background_actor_set_vignette (self,
|
||||
priv->vignette,
|
||||
priv->brightness,
|
||||
g_value_get_double (value));
|
||||
break;
|
||||
case PROP_BRIGHTNESS:
|
||||
meta_background_actor_set_vignette (self,
|
||||
priv->vignette,
|
||||
g_value_get_double (value),
|
||||
priv->vignette_sharpness);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = META_BACKGROUND_ACTOR (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_META_SCREEN:
|
||||
g_value_set_object (value, priv->screen);
|
||||
break;
|
||||
case PROP_MONITOR:
|
||||
g_value_set_int (value, priv->monitor);
|
||||
break;
|
||||
case PROP_BACKGROUND:
|
||||
g_value_set_object (value, priv->background);
|
||||
break;
|
||||
case PROP_VIGNETTE:
|
||||
g_value_set_boolean (value, priv->vignette);
|
||||
break;
|
||||
case PROP_BRIGHTNESS:
|
||||
g_value_set_double (value, priv->brightness);
|
||||
break;
|
||||
case PROP_VIGNETTE_SHARPNESS:
|
||||
g_value_set_double (value, priv->vignette_sharpness);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_class_init (MetaBackgroundActorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *param_spec;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MetaBackgroundActorPrivate));
|
||||
|
||||
object_class->dispose = meta_background_actor_dispose;
|
||||
object_class->set_property = meta_background_actor_set_property;
|
||||
object_class->get_property = meta_background_actor_get_property;
|
||||
|
||||
actor_class->get_preferred_width = meta_background_actor_get_preferred_width;
|
||||
actor_class->get_preferred_height = meta_background_actor_get_preferred_height;
|
||||
actor_class->get_paint_volume = meta_background_actor_get_paint_volume;
|
||||
actor_class->paint = meta_background_actor_paint;
|
||||
|
||||
param_spec = g_param_spec_object ("meta-screen",
|
||||
"MetaScreen",
|
||||
"MetaScreen",
|
||||
META_TYPE_SCREEN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_META_SCREEN,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_int ("monitor",
|
||||
"monitor",
|
||||
"monitor",
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MONITOR,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_object ("background",
|
||||
"Background",
|
||||
"MetaBackground object holding background parameters",
|
||||
META_TYPE_BACKGROUND,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BACKGROUND,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_boolean ("vignette",
|
||||
"Vignette",
|
||||
"Whether vignette effect is enabled",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_VIGNETTE,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_double ("brightness",
|
||||
"Brightness",
|
||||
"Brightness of vignette effect",
|
||||
0.0, 1.0, 1.0,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BRIGHTNESS,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_double ("vignette-sharpness",
|
||||
"Vignette Sharpness",
|
||||
"Sharpness of vignette effect",
|
||||
0.0, G_MAXDOUBLE, 0.0,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_VIGNETTE_SHARPNESS,
|
||||
param_spec);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_init (MetaBackgroundActor *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
META_TYPE_BACKGROUND_ACTOR,
|
||||
MetaBackgroundActorPrivate);
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
|
||||
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
META_TYPE_BACKGROUND_ACTOR,
|
||||
MetaBackgroundActorPrivate);
|
||||
|
||||
priv->vignette = FALSE;
|
||||
priv->brightness = 1.0;
|
||||
priv->vignette_sharpness = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_actor_new:
|
||||
* @monitor: Index of the monitor for which to draw the background
|
||||
*
|
||||
* Creates a new actor to draw the background for the given monitor.
|
||||
* This actor should be associated with a #MetaBackground using
|
||||
* clutter_actor_set_content()
|
||||
*
|
||||
* Return value: the newly created background actor
|
||||
*/
|
||||
ClutterActor *
|
||||
meta_background_actor_new (void)
|
||||
meta_background_actor_new (MetaScreen *screen,
|
||||
int monitor)
|
||||
{
|
||||
MetaBackgroundActor *self;
|
||||
|
||||
self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL);
|
||||
self = g_object_new (META_TYPE_BACKGROUND_ACTOR,
|
||||
"meta-screen", screen,
|
||||
"monitor", monitor,
|
||||
NULL);
|
||||
|
||||
return CLUTTER_ACTOR (self);
|
||||
}
|
||||
@ -185,7 +683,7 @@ cullable_iface_init (MetaCullableInterface *iface)
|
||||
* meta_background_actor_get_clip_region:
|
||||
* @self: a #MetaBackgroundActor
|
||||
*
|
||||
* Return value (transfer full): a #cairo_region_t that represents the part of
|
||||
* Return value (transfer none): a #cairo_region_t that represents the part of
|
||||
* the background not obscured by other #MetaBackgroundActor or
|
||||
* #MetaWindowActor objects.
|
||||
*/
|
||||
@ -193,24 +691,91 @@ cairo_region_t *
|
||||
meta_background_actor_get_clip_region (MetaBackgroundActor *self)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
ClutterActorBox content_box;
|
||||
cairo_rectangle_int_t content_area = { 0 };
|
||||
cairo_region_t *clip_region;
|
||||
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_ACTOR (self), NULL);
|
||||
|
||||
if (!priv->clip_region)
|
||||
return NULL;
|
||||
|
||||
clutter_actor_get_content_box (CLUTTER_ACTOR (self), &content_box);
|
||||
|
||||
content_area.x = content_box.x1;
|
||||
content_area.y = content_box.y1;
|
||||
content_area.width = content_box.x2 - content_box.x1;
|
||||
content_area.height = content_box.y2 - content_box.y1;
|
||||
|
||||
clip_region = cairo_region_create_rectangle (&content_area);
|
||||
cairo_region_intersect (clip_region, priv->clip_region);
|
||||
|
||||
return clip_region;
|
||||
return priv->clip_region;
|
||||
}
|
||||
|
||||
static void
|
||||
invalidate_pipeline (MetaBackgroundActor *self,
|
||||
ChangedFlags changed)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
|
||||
priv->changed |= changed;
|
||||
}
|
||||
|
||||
static void
|
||||
on_background_changed (MetaBackground *background,
|
||||
MetaBackgroundActor *self)
|
||||
{
|
||||
invalidate_pipeline (self, CHANGED_BACKGROUND);
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_actor_set_background (MetaBackgroundActor *self,
|
||||
MetaBackground *background)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
||||
g_return_if_fail (background == NULL || META_IS_BACKGROUND (background));
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
if (background == priv->background)
|
||||
return;
|
||||
|
||||
if (priv->background)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (priv->background,
|
||||
(gpointer)on_background_changed,
|
||||
self);
|
||||
g_object_unref (priv->background);
|
||||
priv->background = NULL;
|
||||
}
|
||||
|
||||
if (background)
|
||||
{
|
||||
priv->background = g_object_ref (background);
|
||||
g_signal_connect (priv->background, "changed",
|
||||
G_CALLBACK (on_background_changed), self);
|
||||
}
|
||||
|
||||
invalidate_pipeline (self, CHANGED_BACKGROUND);
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_actor_set_vignette (MetaBackgroundActor *self,
|
||||
gboolean enabled,
|
||||
double brightness,
|
||||
double sharpness)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
||||
g_return_if_fail (brightness >= 0. && brightness <= 1.);
|
||||
g_return_if_fail (sharpness >= 0.);
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
enabled = enabled != FALSE;
|
||||
|
||||
if (enabled != priv->vignette)
|
||||
{
|
||||
priv->vignette = enabled;
|
||||
invalidate_pipeline (self, CHANGED_EFFECTS);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (brightness != priv->brightness || sharpness != priv->vignette_sharpness)
|
||||
{
|
||||
priv->brightness = brightness;
|
||||
priv->vignette_sharpness = sharpness;
|
||||
invalidate_pipeline (self, CHANGED_VIGNETTE_PARAMETERS);
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
}
|
||||
|
344
src/compositor/meta-background-image.c
Normal file
344
src/compositor/meta-background-image.c
Normal file
@ -0,0 +1,344 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright 2014 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:meta-background-image
|
||||
* @title: MetaBackgroundImage
|
||||
* @short_description: objects holding images loaded from files, used for backgrounds
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <meta/meta-background-image.h>
|
||||
#include "cogl-utils.h"
|
||||
|
||||
enum
|
||||
{
|
||||
LOADED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _MetaBackgroundImageCache
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *images;
|
||||
};
|
||||
|
||||
struct _MetaBackgroundImageCacheClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _MetaBackgroundImage
|
||||
{
|
||||
GObject parent_instance;
|
||||
char *filename;
|
||||
MetaBackgroundImageCache *cache;
|
||||
gboolean in_cache;
|
||||
gboolean loaded;
|
||||
CoglTexture *texture;
|
||||
};
|
||||
|
||||
struct _MetaBackgroundImageClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
|
||||
{
|
||||
cache->images = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_cache_finalize (GObject *object)
|
||||
{
|
||||
MetaBackgroundImageCache *cache = META_BACKGROUND_IMAGE_CACHE (object);
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, cache->images);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
MetaBackgroundImage *image = value;
|
||||
image->in_cache = FALSE;
|
||||
}
|
||||
|
||||
g_hash_table_destroy (cache->images);
|
||||
|
||||
G_OBJECT_CLASS (meta_background_image_cache_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_cache_class_init (MetaBackgroundImageCacheClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_background_image_cache_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_get_default:
|
||||
*
|
||||
* Return value: (transfer none): the global singleton background cache
|
||||
*/
|
||||
MetaBackgroundImageCache *
|
||||
meta_background_image_cache_get_default (void)
|
||||
{
|
||||
static MetaBackgroundImageCache *cache;
|
||||
|
||||
if (cache == NULL)
|
||||
cache = g_object_new (META_TYPE_BACKGROUND_IMAGE_CACHE, NULL);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void
|
||||
load_file (GTask *task,
|
||||
MetaBackgroundImage *image,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (image->filename,
|
||||
&error);
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, pixbuf, (GDestroyNotify) g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
file_loaded (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (source_object);
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
CoglTexture *texture;
|
||||
GdkPixbuf *pixbuf;
|
||||
int width, height, row_stride;
|
||||
guchar *pixels;
|
||||
gboolean has_alpha;
|
||||
|
||||
task = G_TASK (result);
|
||||
pixbuf = g_task_propagate_pointer (task, &error);
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
g_warning ("Failed to load background '%s': %s",
|
||||
image->filename, error->message);
|
||||
g_clear_error (&error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
width = gdk_pixbuf_get_width (pixbuf);
|
||||
height = gdk_pixbuf_get_height (pixbuf);
|
||||
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
|
||||
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
||||
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
||||
|
||||
texture = meta_create_texture (width, height,
|
||||
has_alpha ? COGL_TEXTURE_COMPONENTS_RGBA : COGL_TEXTURE_COMPONENTS_RGB,
|
||||
META_TEXTURE_ALLOW_SLICING);
|
||||
|
||||
if (!cogl_texture_set_data (texture,
|
||||
has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
|
||||
row_stride,
|
||||
pixels, 0,
|
||||
NULL))
|
||||
{
|
||||
g_warning ("Failed to create texture for background");
|
||||
cogl_object_unref (texture);
|
||||
}
|
||||
|
||||
image->texture = texture;
|
||||
|
||||
out:
|
||||
image->loaded = TRUE;
|
||||
g_signal_emit (image, signals[LOADED], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_load:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
* @filename: filename to load
|
||||
*
|
||||
* Loads an image to use as a background, or returns a reference to an
|
||||
* image that is already in the process of loading or loaded. In either
|
||||
* case, what is returned is a #MetaBackgroundImage which can be derefenced
|
||||
* to get a #CoglTexture. If meta_background_image_is_loaded() returns %TRUE,
|
||||
* the background is loaded, otherwise the MetaBackgroundImage::loaded
|
||||
* signal will be emitted exactly once. The 'loaded' state means that the
|
||||
* loading process finished, whether it succeeded or failed.
|
||||
*
|
||||
* Return value: (transfer full): a #MetaBackgroundImage to dereference to get the loaded texture
|
||||
*/
|
||||
MetaBackgroundImage *
|
||||
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
|
||||
const char *filename)
|
||||
{
|
||||
MetaBackgroundImage *image;
|
||||
GTask *task;
|
||||
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
|
||||
image = g_hash_table_lookup (cache->images, filename);
|
||||
if (image != NULL)
|
||||
return g_object_ref (image);
|
||||
|
||||
image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
|
||||
image->cache = cache;
|
||||
image->in_cache = TRUE;
|
||||
image->filename = g_strdup (filename);
|
||||
g_hash_table_insert (cache->images, image->filename, image);
|
||||
|
||||
task = g_task_new (image, NULL, file_loaded, NULL);
|
||||
|
||||
g_task_run_in_thread (task, (GTaskThreadFunc) load_file);
|
||||
g_object_unref (task);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_purge:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
* @filename: filename to remove from the cache
|
||||
*
|
||||
* Remove an entry from the cache; this would be used if monitoring
|
||||
* showed that the file changed.
|
||||
*/
|
||||
void
|
||||
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
|
||||
const char *filename)
|
||||
{
|
||||
MetaBackgroundImage *image;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
|
||||
g_return_if_fail (filename != NULL);
|
||||
|
||||
image = g_hash_table_lookup (cache->images, filename);
|
||||
if (image == NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (cache->images, image->filename);
|
||||
image->in_cache = FALSE;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (MetaBackgroundImage, meta_background_image, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
meta_background_image_init (MetaBackgroundImage *image)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_finalize (GObject *object)
|
||||
{
|
||||
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
|
||||
|
||||
if (image->in_cache)
|
||||
g_hash_table_remove (image->cache->images, image->filename);
|
||||
|
||||
if (image->texture)
|
||||
cogl_object_unref (image->texture);
|
||||
if (image->filename)
|
||||
g_free (image->filename);
|
||||
|
||||
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_class_init (MetaBackgroundImageClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_background_image_finalize;
|
||||
|
||||
signals[LOADED] =
|
||||
g_signal_new ("loaded",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_is_loaded:
|
||||
* @image: a #MetaBackgroundImage
|
||||
*
|
||||
* Return value: %TRUE if loading has already completed, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
meta_background_image_is_loaded (MetaBackgroundImage *image)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE);
|
||||
|
||||
return image->loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_get_success:
|
||||
* @image: a #MetaBackgroundImage
|
||||
*
|
||||
* This function is a convenience function for checking for success,
|
||||
* without having to call meta_background_image_get_texture() and
|
||||
* handle the return of a Cogl type.
|
||||
*
|
||||
* Return value: %TRUE if loading completed successfully, otherwise %FALSE
|
||||
*/
|
||||
gboolean
|
||||
meta_background_image_get_success (MetaBackgroundImage *image)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE);
|
||||
|
||||
return image->texture != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_get_texture:
|
||||
* @image: a #MetaBackgroundImage
|
||||
*
|
||||
* Return value: (transfer none): a #CoglTexture if loading succeeded; if
|
||||
* loading failed or has not yet finished, %NULL.
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_background_image_get_texture (MetaBackgroundImage *image)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), NULL);
|
||||
|
||||
return image->texture;
|
||||
}
|
15
src/compositor/meta-background-private.h
Normal file
15
src/compositor/meta-background-private.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#ifndef META_BACKGROUND_PRIVATE_H
|
||||
#define META_BACKGROUND_PRIVATE_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "meta-background-private.h"
|
||||
|
||||
CoglTexture *meta_background_get_texture (MetaBackground *self,
|
||||
int monitor_index,
|
||||
cairo_rectangle_int_t *texture_area,
|
||||
CoglPipelineWrapMode *wrap_mode);
|
||||
|
||||
#endif /* META_BACKGROUND_PRIVATE_H */
|
File diff suppressed because it is too large
Load Diff
@ -170,6 +170,15 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
klass->minimize (plugin, actor);
|
||||
}
|
||||
break;
|
||||
case META_PLUGIN_UNMINIMIZE:
|
||||
if (klass->unminimize)
|
||||
{
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
klass->unminimize (plugin, actor);
|
||||
}
|
||||
break;
|
||||
case META_PLUGIN_MAP:
|
||||
if (klass->map)
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define META_PLUGIN_MAP (1<<3)
|
||||
#define META_PLUGIN_DESTROY (1<<4)
|
||||
#define META_PLUGIN_SWITCH_WORKSPACE (1<<5)
|
||||
#define META_PLUGIN_UNMINIMIZE (1<<6)
|
||||
|
||||
#define META_PLUGIN_ALL_EFFECTS (~0)
|
||||
|
||||
|
@ -110,6 +110,13 @@ meta_plugin_minimize_completed (MetaPlugin *plugin,
|
||||
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MINIMIZE);
|
||||
}
|
||||
|
||||
void
|
||||
meta_plugin_unminimize_completed (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor)
|
||||
{
|
||||
meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_UNMINIMIZE);
|
||||
}
|
||||
|
||||
void
|
||||
meta_plugin_maximize_completed (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor)
|
||||
|
@ -541,7 +541,7 @@ blur_xspan (guchar *row,
|
||||
* be well predicted and there are enough different possibilities
|
||||
* that trying to write this as a series of unconditional loops
|
||||
* is hard and not an obvious win. The main slow down here seems
|
||||
* to be the integer division for pixel; one possible optimization
|
||||
* to be the integer division per pixel; one possible optimization
|
||||
* would be to accumulate into two 16-bit integer buffers and
|
||||
* only divide down after all three passes. (SSE parallel implementation
|
||||
* of the divide step is possible.)
|
||||
@ -549,27 +549,27 @@ blur_xspan (guchar *row,
|
||||
for (i = x0 - d + offset; i < x1 + offset; i++)
|
||||
{
|
||||
if (i >= 0 && i < row_width)
|
||||
sum += row[i];
|
||||
sum += row[i];
|
||||
|
||||
if (i >= x0 + offset)
|
||||
{
|
||||
if (i >= d)
|
||||
sum -= row[i - d];
|
||||
{
|
||||
if (i >= d)
|
||||
sum -= row[i - d];
|
||||
|
||||
tmp_buffer[i - offset] = (sum + d / 2) / d;
|
||||
}
|
||||
tmp_buffer[i - offset] = (sum + d / 2) / d;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(row + x0, tmp_buffer + x0, x1 - x0);
|
||||
memcpy (row + x0, tmp_buffer + x0, x1 - x0);
|
||||
}
|
||||
|
||||
static void
|
||||
blur_rows (cairo_region_t *convolve_region,
|
||||
int x_offset,
|
||||
int y_offset,
|
||||
guchar *buffer,
|
||||
int buffer_width,
|
||||
int buffer_height,
|
||||
guchar *buffer,
|
||||
int buffer_width,
|
||||
int buffer_height,
|
||||
int d)
|
||||
{
|
||||
int i, j;
|
||||
@ -586,30 +586,30 @@ blur_rows (cairo_region_t *convolve_region,
|
||||
cairo_region_get_rectangle (convolve_region, i, &rect);
|
||||
|
||||
for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
|
||||
{
|
||||
guchar *row = buffer + j * buffer_width;
|
||||
int x0 = x_offset + rect.x;
|
||||
int x1 = x0 + rect.width;
|
||||
{
|
||||
guchar *row = buffer + j * buffer_width;
|
||||
int x0 = x_offset + rect.x;
|
||||
int x1 = x0 + rect.width;
|
||||
|
||||
/* We want to produce a symmetric blur that spreads a pixel
|
||||
* equally far to the left and right. If d is odd that happens
|
||||
* naturally, but for d even, we approximate by using a blur
|
||||
* on either side and then a centered blur of size d + 1.
|
||||
* (techique also from the SVG specification)
|
||||
* (technique also from the SVG specification)
|
||||
*/
|
||||
if (d % 2 == 1)
|
||||
{
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 1);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, -1);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d + 1, 0);
|
||||
}
|
||||
}
|
||||
if (d % 2 == 1)
|
||||
{
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, 1);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d, -1);
|
||||
blur_xspan (row, tmp_buffer, buffer_width, x0, x1, d + 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (tmp_buffer);
|
||||
@ -634,7 +634,7 @@ fade_bytes (guchar *bytes,
|
||||
*/
|
||||
static guchar *
|
||||
flip_buffer (guchar *buffer,
|
||||
int width,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
/* Working in blocks increases cache efficiency, compared to reading
|
||||
@ -646,33 +646,33 @@ flip_buffer (guchar *buffer,
|
||||
int i0, j0;
|
||||
|
||||
for (j0 = 0; j0 < height; j0 += BLOCK_SIZE)
|
||||
for (i0 = 0; i0 <= j0; i0 += BLOCK_SIZE)
|
||||
{
|
||||
int max_j = MIN(j0 + BLOCK_SIZE, height);
|
||||
int max_i = MIN(i0 + BLOCK_SIZE, width);
|
||||
int i, j;
|
||||
for (i0 = 0; i0 <= j0; i0 += BLOCK_SIZE)
|
||||
{
|
||||
int max_j = MIN(j0 + BLOCK_SIZE, height);
|
||||
int max_i = MIN(i0 + BLOCK_SIZE, width);
|
||||
int i, j;
|
||||
|
||||
if (i0 == j0)
|
||||
{
|
||||
for (j = j0; j < max_j; j++)
|
||||
for (i = i0; i < j; i++)
|
||||
{
|
||||
guchar tmp = buffer[j * width + i];
|
||||
buffer[j * width + i] = buffer[i * width + j];
|
||||
buffer[i * width + j] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = j0; j < max_j; j++)
|
||||
for (i = i0; i < max_i; i++)
|
||||
{
|
||||
guchar tmp = buffer[j * width + i];
|
||||
buffer[j * width + i] = buffer[i * width + j];
|
||||
buffer[i * width + j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i0 == j0)
|
||||
{
|
||||
for (j = j0; j < max_j; j++)
|
||||
for (i = i0; i < j; i++)
|
||||
{
|
||||
guchar tmp = buffer[j * width + i];
|
||||
buffer[j * width + i] = buffer[i * width + j];
|
||||
buffer[i * width + j] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = j0; j < max_j; j++)
|
||||
for (i = i0; i < max_i; i++)
|
||||
{
|
||||
guchar tmp = buffer[j * width + i];
|
||||
buffer[j * width + i] = buffer[i * width + j];
|
||||
buffer[i * width + j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@ -683,15 +683,15 @@ flip_buffer (guchar *buffer,
|
||||
|
||||
for (i0 = 0; i0 < width; i0 += BLOCK_SIZE)
|
||||
for (j0 = 0; j0 < height; j0 += BLOCK_SIZE)
|
||||
{
|
||||
int max_j = MIN(j0 + BLOCK_SIZE, height);
|
||||
int max_i = MIN(i0 + BLOCK_SIZE, width);
|
||||
int i, j;
|
||||
{
|
||||
int max_j = MIN(j0 + BLOCK_SIZE, height);
|
||||
int max_i = MIN(i0 + BLOCK_SIZE, width);
|
||||
int i, j;
|
||||
|
||||
for (i = i0; i < max_i; i++)
|
||||
for (j = j0; j < max_j; j++)
|
||||
new_buffer[i * height + j] = buffer[j * width + i];
|
||||
}
|
||||
new_buffer[i * height + j] = buffer[j * width + i];
|
||||
}
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
@ -704,6 +704,8 @@ static void
|
||||
make_shadow (MetaShadow *shadow,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||
int d = get_box_filter_size (shadow->key.radius);
|
||||
int spread = get_shadow_spread (shadow->key.radius);
|
||||
cairo_rectangle_int_t extents;
|
||||
@ -763,7 +765,7 @@ make_shadow (MetaShadow *shadow,
|
||||
|
||||
cairo_region_get_rectangle (region, k, &rect);
|
||||
for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
|
||||
memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width);
|
||||
memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width);
|
||||
}
|
||||
|
||||
/* Step 2: swap rows and columns */
|
||||
@ -793,15 +795,15 @@ make_shadow (MetaShadow *shadow,
|
||||
* in the case of top_fade >= 0. We also account for padding at the left for symmetry
|
||||
* though that doesn't currently occur.
|
||||
*/
|
||||
shadow->texture = cogl_texture_new_from_data (shadow->outer_border_left + extents.width + shadow->outer_border_right,
|
||||
shadow->outer_border_top + extents.height + shadow->outer_border_bottom,
|
||||
COGL_TEXTURE_NONE,
|
||||
COGL_PIXEL_FORMAT_A_8,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
buffer_width,
|
||||
(buffer +
|
||||
(y_offset - shadow->outer_border_top) * buffer_width +
|
||||
(x_offset - shadow->outer_border_left)));
|
||||
shadow->texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx,
|
||||
shadow->outer_border_left + extents.width + shadow->outer_border_right,
|
||||
shadow->outer_border_top + extents.height + shadow->outer_border_bottom,
|
||||
COGL_PIXEL_FORMAT_A_8,
|
||||
buffer_width,
|
||||
(buffer +
|
||||
(y_offset - shadow->outer_border_top) * buffer_width +
|
||||
(x_offset - shadow->outer_border_left)),
|
||||
NULL));
|
||||
|
||||
cairo_region_destroy (row_convolve_region);
|
||||
cairo_region_destroy (column_convolve_region);
|
||||
|
@ -32,8 +32,6 @@
|
||||
ClutterActor *meta_shaped_texture_new (void);
|
||||
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *texture);
|
||||
gboolean meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *stex,
|
||||
cairo_rectangle_int_t *unobscured_bounds);
|
||||
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
|
||||
|
||||
#endif
|
||||
|
@ -28,16 +28,14 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
#include <meta/util.h>
|
||||
#include "meta-shaped-texture-private.h"
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
|
||||
|
||||
#include "clutter-utils.h"
|
||||
#include "meta-texture-tower.h"
|
||||
|
||||
#include "meta-shaped-texture-private.h"
|
||||
#include "meta-window-actor-private.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl.h>
|
||||
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
|
||||
#include "meta-cullable.h"
|
||||
|
||||
static void meta_shaped_texture_dispose (GObject *object);
|
||||
@ -65,6 +63,14 @@ G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_AC
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
|
||||
MetaShapedTexturePrivate))
|
||||
|
||||
enum {
|
||||
SIZE_CHANGED,
|
||||
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
struct _MetaShapedTexturePrivate
|
||||
{
|
||||
MetaTextureTower *paint_tower;
|
||||
@ -97,6 +103,13 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
|
||||
actor_class->paint = meta_shaped_texture_paint;
|
||||
actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume;
|
||||
|
||||
signals[SIZE_CHANGED] = g_signal_new ("size-changed",
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
|
||||
}
|
||||
|
||||
@ -249,22 +262,20 @@ set_cogl_texture (MetaShapedTexture *stex,
|
||||
cogl_object_ref (cogl_tex);
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (width != priv->tex_width ||
|
||||
height != priv->tex_height)
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* size changed to 0 going to an invalid handle */
|
||||
priv->tex_width = 0;
|
||||
priv->tex_height = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
if (priv->tex_width != width ||
|
||||
priv->tex_height != height)
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
|
||||
}
|
||||
|
||||
/* NB: We don't queue a redraw of the actor here because we don't
|
||||
@ -285,10 +296,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
guchar opacity;
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *pipeline = NULL;
|
||||
CoglTexture *paint_tex;
|
||||
ClutterActorBox alloc;
|
||||
cairo_region_t *blended_region = NULL;
|
||||
CoglPipelineFilter filter;
|
||||
|
||||
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
||||
@ -326,13 +335,15 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
||||
return;
|
||||
|
||||
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
||||
|
||||
/* Use nearest-pixel interpolation if the texture is unscaled. This
|
||||
* improves performance, especially with software rendering.
|
||||
*/
|
||||
|
||||
filter = COGL_PIPELINE_FILTER_LINEAR;
|
||||
|
||||
if (!clutter_actor_is_in_clone_paint (actor) && meta_actor_is_untransformed (actor, NULL, NULL))
|
||||
if (meta_actor_painting_untransformed (tex_width, tex_height, NULL, NULL))
|
||||
filter = COGL_PIPELINE_FILTER_NEAREST;
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
@ -341,7 +352,45 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
opacity = clutter_actor_get_paint_opacity (actor);
|
||||
clutter_actor_get_allocation_box (actor, &alloc);
|
||||
|
||||
if (priv->opaque_region != NULL && opacity == 255)
|
||||
cairo_region_t *blended_region;
|
||||
gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255);
|
||||
|
||||
if (use_opaque_region)
|
||||
{
|
||||
if (priv->clip_region != NULL)
|
||||
blended_region = cairo_region_copy (priv->clip_region);
|
||||
else
|
||||
blended_region = cairo_region_create_rectangle (&tex_rect);
|
||||
|
||||
cairo_region_subtract (blended_region, priv->opaque_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->clip_region != NULL)
|
||||
blended_region = cairo_region_reference (priv->clip_region);
|
||||
else
|
||||
blended_region = NULL;
|
||||
}
|
||||
|
||||
/* Limit to how many separate rectangles we'll draw; beyond this just
|
||||
* fall back and draw the whole thing */
|
||||
#define MAX_RECTS 16
|
||||
|
||||
if (blended_region != NULL)
|
||||
{
|
||||
int n_rects = cairo_region_num_rectangles (blended_region);
|
||||
if (n_rects > MAX_RECTS)
|
||||
{
|
||||
/* Fall back to taking the fully blended path. */
|
||||
use_opaque_region = FALSE;
|
||||
|
||||
cairo_region_destroy (blended_region);
|
||||
blended_region = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* First, paint the unblended parts, which are part of the opaque region. */
|
||||
if (use_opaque_region)
|
||||
{
|
||||
CoglPipeline *opaque_pipeline;
|
||||
cairo_region_t *region;
|
||||
@ -358,103 +407,87 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
region = cairo_region_reference (priv->opaque_region);
|
||||
}
|
||||
|
||||
if (cairo_region_is_empty (region))
|
||||
goto paint_blended;
|
||||
|
||||
opaque_pipeline = get_unblended_pipeline (ctx);
|
||||
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
|
||||
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
if (!cairo_region_is_empty (region))
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
|
||||
opaque_pipeline = get_unblended_pipeline (ctx);
|
||||
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
|
||||
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (region);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_region_get_rectangle (region, i, &rect);
|
||||
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
|
||||
}
|
||||
|
||||
cogl_object_unref (opaque_pipeline);
|
||||
}
|
||||
|
||||
cogl_object_unref (opaque_pipeline);
|
||||
|
||||
if (priv->clip_region != NULL)
|
||||
{
|
||||
blended_region = cairo_region_copy (priv->clip_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
|
||||
blended_region = cairo_region_create_rectangle (&rect);
|
||||
}
|
||||
|
||||
cairo_region_subtract (blended_region, priv->opaque_region);
|
||||
|
||||
paint_blended:
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
if (blended_region == NULL && priv->clip_region != NULL)
|
||||
blended_region = cairo_region_reference (priv->clip_region);
|
||||
/* Now, go ahead and paint the blended parts. */
|
||||
|
||||
if (blended_region != NULL && cairo_region_is_empty (blended_region))
|
||||
goto out;
|
||||
|
||||
if (priv->mask_texture == NULL)
|
||||
/* We have three cases:
|
||||
* 1) blended_region has rectangles - paint the rectangles.
|
||||
* 2) blended_region is empty - don't paint anything
|
||||
* 3) blended_region is NULL - paint fully-blended.
|
||||
*
|
||||
* 1) and 3) are the times where we have to paint stuff. This tests
|
||||
* for 1) and 3).
|
||||
*/
|
||||
if (blended_region == NULL || !cairo_region_is_empty (blended_region))
|
||||
{
|
||||
pipeline = get_unmasked_pipeline (ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline = get_masked_pipeline (ctx);
|
||||
cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
|
||||
cogl_pipeline_set_layer_filters (pipeline, 1, filter, filter);
|
||||
}
|
||||
CoglPipeline *blended_pipeline;
|
||||
|
||||
cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex);
|
||||
cogl_pipeline_set_layer_filters (pipeline, 0, filter, filter);
|
||||
if (priv->mask_texture == NULL)
|
||||
{
|
||||
blended_pipeline = get_unmasked_pipeline (ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
blended_pipeline = get_masked_pipeline (ctx);
|
||||
cogl_pipeline_set_layer_texture (blended_pipeline, 1, priv->mask_texture);
|
||||
cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter);
|
||||
}
|
||||
|
||||
{
|
||||
CoglColor color;
|
||||
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
||||
cogl_pipeline_set_color (pipeline, &color);
|
||||
}
|
||||
cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex);
|
||||
cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter);
|
||||
|
||||
if (blended_region != NULL)
|
||||
{
|
||||
int n_rects;
|
||||
CoglColor color;
|
||||
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
||||
cogl_pipeline_set_color (blended_pipeline, &color);
|
||||
|
||||
/* Limit to how many separate rectangles we'll draw; beyond this just
|
||||
* fall back and draw the whole thing */
|
||||
# define MAX_RECTS 16
|
||||
|
||||
n_rects = cairo_region_num_rectangles (blended_region);
|
||||
if (n_rects <= MAX_RECTS)
|
||||
{
|
||||
if (blended_region != NULL)
|
||||
{
|
||||
/* 1) blended_region is not empty. Paint the rectangles. */
|
||||
int i;
|
||||
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
||||
int n_rects = cairo_region_num_rectangles (blended_region);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_region_get_rectangle (blended_region, i, &rect);
|
||||
|
||||
cairo_region_get_rectangle (blended_region, i, &rect);
|
||||
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
||||
continue;
|
||||
|
||||
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
||||
continue;
|
||||
|
||||
paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
|
||||
paint_clipped_rectangle (fb, blended_pipeline, &rect, &alloc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 3) blended_region is NULL. Do a full paint. */
|
||||
cogl_framebuffer_draw_rectangle (fb, blended_pipeline,
|
||||
0, 0,
|
||||
alloc.x2 - alloc.x1,
|
||||
alloc.y2 - alloc.y1);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
cogl_object_unref (blended_pipeline);
|
||||
}
|
||||
|
||||
cogl_framebuffer_draw_rectangle (fb, pipeline,
|
||||
0, 0,
|
||||
alloc.x2 - alloc.x1,
|
||||
alloc.y2 - alloc.y1);
|
||||
|
||||
out:
|
||||
if (pipeline != NULL)
|
||||
cogl_object_unref (pipeline);
|
||||
if (blended_region != NULL)
|
||||
cairo_region_destroy (blended_region);
|
||||
}
|
||||
@ -472,7 +505,7 @@ meta_shaped_texture_get_preferred_width (ClutterActor *self,
|
||||
priv = META_SHAPED_TEXTURE (self)->priv;
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p = 0;
|
||||
*min_width_p = priv->tex_width;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = priv->tex_width;
|
||||
@ -491,43 +524,70 @@ meta_shaped_texture_get_preferred_height (ClutterActor *self,
|
||||
priv = META_SHAPED_TEXTURE (self)->priv;
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p = 0;
|
||||
*min_height_p = priv->tex_height;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = priv->tex_height;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
effective_unobscured_region (MetaShapedTexture *self)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv = self->priv;
|
||||
ClutterActor *actor;
|
||||
|
||||
/* Fail if we have any mapped clones. */
|
||||
actor = CLUTTER_ACTOR (self);
|
||||
do
|
||||
{
|
||||
if (clutter_actor_has_mapped_clones (actor))
|
||||
return NULL;
|
||||
actor = clutter_actor_get_parent (actor);
|
||||
}
|
||||
while (actor != NULL);
|
||||
|
||||
return priv->unobscured_region;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_unobscured_bounds (MetaShapedTexture *self,
|
||||
cairo_rectangle_int_t *unobscured_bounds)
|
||||
{
|
||||
cairo_region_t *unobscured_region = effective_unobscured_region (self);
|
||||
|
||||
if (unobscured_region)
|
||||
{
|
||||
cairo_region_get_extents (unobscured_region, unobscured_bounds);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_shaped_texture_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume)
|
||||
{
|
||||
MetaShapedTexture *self = META_SHAPED_TEXTURE (actor);
|
||||
ClutterActorBox box;
|
||||
cairo_rectangle_int_t unobscured_bounds;
|
||||
|
||||
if (!clutter_paint_volume_set_from_allocation (volume, actor))
|
||||
if (!clutter_actor_has_allocation (actor))
|
||||
return FALSE;
|
||||
|
||||
if (meta_shaped_texture_get_unobscured_bounds (self, &unobscured_bounds))
|
||||
clutter_actor_get_allocation_box (actor, &box);
|
||||
|
||||
if (get_unobscured_bounds (self, &unobscured_bounds))
|
||||
{
|
||||
ClutterVertex origin;
|
||||
cairo_rectangle_int_t bounds;
|
||||
|
||||
/* I hate ClutterPaintVolume so much... */
|
||||
clutter_paint_volume_get_origin (volume, &origin);
|
||||
bounds.x = origin.x;
|
||||
bounds.y = origin.y;
|
||||
bounds.width = clutter_paint_volume_get_width (volume);
|
||||
bounds.height = clutter_paint_volume_get_height (volume);
|
||||
|
||||
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
|
||||
|
||||
origin.x = bounds.x;
|
||||
origin.y = bounds.y;
|
||||
clutter_paint_volume_set_origin (volume, &origin);
|
||||
clutter_paint_volume_set_width (volume, bounds.width);
|
||||
clutter_paint_volume_set_height (volume, bounds.height);
|
||||
box.x1 = MAX (unobscured_bounds.x, box.x1);
|
||||
box.x2 = MIN (unobscured_bounds.x + unobscured_bounds.width, box.x2);
|
||||
box.y1 = MAX (unobscured_bounds.y, box.y1);
|
||||
box.y2 = MIN (unobscured_bounds.y + unobscured_bounds.height, box.y2);
|
||||
}
|
||||
box.x2 = MAX (box.x2, box.x1);
|
||||
box.y2 = MAX (box.y2, box.y1);
|
||||
|
||||
clutter_paint_volume_union_box (volume, &box);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -573,39 +633,6 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
effective_unobscured_region (MetaShapedTexture *self)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv = self->priv;
|
||||
ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR (self));
|
||||
|
||||
if (clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)))
|
||||
return NULL;
|
||||
|
||||
while (parent && !META_IS_WINDOW_ACTOR (parent))
|
||||
parent = clutter_actor_get_parent (parent);
|
||||
|
||||
if (parent && clutter_actor_has_mapped_clones (parent))
|
||||
return NULL;
|
||||
|
||||
return priv->unobscured_region;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *self,
|
||||
cairo_rectangle_int_t *unobscured_bounds)
|
||||
{
|
||||
cairo_region_t *unobscured_region = effective_unobscured_region (self);
|
||||
|
||||
if (unobscured_region)
|
||||
{
|
||||
cairo_region_get_extents (unobscured_region, unobscured_bounds);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_shaped_texture_is_obscured (MetaShapedTexture *self)
|
||||
{
|
||||
|
@ -34,45 +34,15 @@
|
||||
struct _MetaSurfaceActorWaylandPrivate
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
};
|
||||
typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorWayland, meta_surface_actor_wayland, META_TYPE_SURFACE_ACTOR)
|
||||
|
||||
static void
|
||||
meta_surface_actor_handle_buffer_destroy (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = wl_container_of (listener, priv, buffer_destroy_listener);
|
||||
|
||||
/* If the buffer is destroyed while we're attached to it,
|
||||
* we want to unset priv->buffer so we don't access freed
|
||||
* memory. Keep the texture set however so the user doesn't
|
||||
* see the window disappear. */
|
||||
priv->buffer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
|
||||
if (priv->buffer)
|
||||
{
|
||||
struct wl_resource *resource = priv->buffer->resource;
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
|
||||
|
||||
if (shm_buffer)
|
||||
{
|
||||
CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture);
|
||||
cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL);
|
||||
}
|
||||
|
||||
meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -109,7 +79,7 @@ meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor)
|
||||
}
|
||||
|
||||
static int
|
||||
get_output_scale (int output_id)
|
||||
get_output_scale (int winsys_id)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
|
||||
MetaOutput *outputs;
|
||||
@ -120,7 +90,7 @@ get_output_scale (int output_id)
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
if (outputs[i].output_id == output_id)
|
||||
if (outputs[i].winsys_id == winsys_id)
|
||||
{
|
||||
output_scale = outputs[i].scale;
|
||||
break;
|
||||
@ -150,7 +120,7 @@ meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *actor)
|
||||
|
||||
/* XXX: We do not handle x11 clients yet */
|
||||
if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11)
|
||||
output_scale = get_output_scale (window->monitor->output_id);
|
||||
output_scale = get_output_scale (window->monitor->winsys_id);
|
||||
|
||||
return (double)output_scale / (double)priv->surface->scale;
|
||||
}
|
||||
@ -213,7 +183,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
|
||||
{
|
||||
MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object);
|
||||
|
||||
meta_surface_actor_wayland_set_buffer (self, NULL);
|
||||
meta_surface_actor_wayland_set_texture (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object);
|
||||
}
|
||||
@ -244,9 +214,6 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
|
||||
static void
|
||||
meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
|
||||
priv->buffer_destroy_listener.notify = meta_surface_actor_handle_buffer_destroy;
|
||||
}
|
||||
|
||||
MetaSurfaceActor *
|
||||
@ -263,24 +230,11 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
|
||||
MetaWaylandBuffer *buffer)
|
||||
meta_surface_actor_wayland_set_texture (MetaSurfaceActorWayland *self,
|
||||
CoglTexture *texture)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||
|
||||
if (priv->buffer)
|
||||
wl_list_remove (&priv->buffer_destroy_listener.link);
|
||||
|
||||
priv->buffer = buffer;
|
||||
|
||||
if (priv->buffer)
|
||||
{
|
||||
wl_signal_add (&priv->buffer->destroy_signal, &priv->buffer_destroy_listener);
|
||||
meta_shaped_texture_set_texture (stex, priv->buffer->texture);
|
||||
}
|
||||
else
|
||||
meta_shaped_texture_set_texture (stex, NULL);
|
||||
meta_shaped_texture_set_texture (stex, texture);
|
||||
}
|
||||
|
||||
MetaWaylandSurface *
|
||||
|
@ -58,8 +58,8 @@ GType meta_surface_actor_wayland_get_type (void);
|
||||
MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface);
|
||||
MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self);
|
||||
|
||||
void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
|
||||
MetaWaylandBuffer *buffer);
|
||||
void meta_surface_actor_wayland_set_texture (MetaSurfaceActorWayland *self,
|
||||
CoglTexture *texture);
|
||||
|
||||
double meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *actor);
|
||||
|
||||
|
@ -179,19 +179,6 @@ is_visible (MetaSurfaceActorX11 *self)
|
||||
return (priv->pixmap != None) && !priv->unredirected;
|
||||
}
|
||||
|
||||
static void
|
||||
damage_area (MetaSurfaceActorX11 *self,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
if (!is_visible (self))
|
||||
return;
|
||||
|
||||
cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height);
|
||||
meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height)
|
||||
@ -218,11 +205,10 @@ meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
|
||||
priv->does_full_damage = TRUE;
|
||||
}
|
||||
|
||||
/* Drop damage event for unredirected windows */
|
||||
if (priv->unredirected)
|
||||
if (!is_visible (self))
|
||||
return;
|
||||
|
||||
damage_area (self, x, y, width, height);
|
||||
cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -239,26 +225,6 @@ meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor)
|
||||
XDamageSubtract (xdisplay, priv->damage, None, None);
|
||||
meta_error_trap_pop (display);
|
||||
|
||||
/* We need to make sure that any X drawing that happens before the
|
||||
* XDamageSubtract() above is visible to subsequent GL rendering;
|
||||
* the only standardized way to do this is EXT_x11_sync_object,
|
||||
* which isn't yet widely available. For now, we count on details
|
||||
* of Xorg and the open source drivers, and hope for the best
|
||||
* otherwise.
|
||||
*
|
||||
* Xorg and open source driver specifics:
|
||||
*
|
||||
* The X server makes sure to flush drawing to the kernel before
|
||||
* sending out damage events, but since we use DamageReportBoundingBox
|
||||
* there may be drawing between the last damage event and the
|
||||
* XDamageSubtract() that needs to be flushed as well.
|
||||
*
|
||||
* Xorg always makes sure that drawing is flushed to the kernel
|
||||
* before writing events or responses to the client, so any round trip
|
||||
* request at this point is sufficient to flush the GLX buffers.
|
||||
*/
|
||||
XSync (xdisplay, False);
|
||||
|
||||
priv->received_damage = FALSE;
|
||||
}
|
||||
|
||||
|
@ -36,20 +36,13 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_
|
||||
|
||||
enum {
|
||||
REPAINT_SCHEDULED,
|
||||
SIZE_CHANGED,
|
||||
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
|
||||
cairo_rectangle_int_t *unobscured_bounds)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_pick (ClutterActor *actor,
|
||||
const ClutterColor *color)
|
||||
@ -128,6 +121,13 @@ meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
signals[SIZE_CHANGED] = g_signal_new ("size-changed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
|
||||
}
|
||||
|
||||
@ -152,6 +152,14 @@ cullable_iface_init (MetaCullableInterface *iface)
|
||||
iface->reset_culling = meta_surface_actor_reset_culling;
|
||||
}
|
||||
|
||||
static void
|
||||
texture_size_changed (MetaShapedTexture *texture,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaSurfaceActor *actor = META_SURFACE_ACTOR (user_data);
|
||||
g_signal_emit (actor, signals[SIZE_CHANGED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_init (MetaSurfaceActor *self)
|
||||
{
|
||||
@ -162,6 +170,8 @@ meta_surface_actor_init (MetaSurfaceActor *self)
|
||||
MetaSurfaceActorPrivate);
|
||||
|
||||
priv->texture = META_SHAPED_TEXTURE (meta_shaped_texture_new ());
|
||||
g_signal_connect_object (priv->texture, "size-changed",
|
||||
G_CALLBACK (texture_size_changed), self, 0);
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->texture));
|
||||
}
|
||||
|
||||
@ -178,7 +188,7 @@ meta_surface_actor_get_texture (MetaSurfaceActor *self)
|
||||
return self->priv->texture;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
meta_surface_actor_update_area (MetaSurfaceActor *self,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
@ -252,6 +262,9 @@ meta_surface_actor_process_damage (MetaSurfaceActor *self,
|
||||
}
|
||||
|
||||
META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height);
|
||||
|
||||
if (meta_surface_actor_is_visible (self))
|
||||
meta_surface_actor_update_area (self, x, y, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
@ -267,9 +280,15 @@ meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
|
||||
CoglTexture *texture = meta_shaped_texture_get_texture (stex);
|
||||
|
||||
/* If we don't have a texture, like during initialization, assume
|
||||
* that we're ARGB32. */
|
||||
* that we're ARGB32.
|
||||
*
|
||||
* If we are unredirected and we have no texture assume that we are
|
||||
* not ARGB32 otherwise we wouldn't be unredirected in the first
|
||||
* place. This prevents us from continually redirecting and
|
||||
* unredirecting on every paint.
|
||||
*/
|
||||
if (!texture)
|
||||
return TRUE;
|
||||
return !meta_surface_actor_is_unredirected (self);
|
||||
|
||||
switch (cogl_texture_get_components (texture))
|
||||
{
|
||||
|
@ -55,17 +55,12 @@ MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self);
|
||||
MetaWindow *meta_surface_actor_get_window (MetaSurfaceActor *self);
|
||||
|
||||
gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self);
|
||||
gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
|
||||
cairo_rectangle_int_t *unobscured_bounds);
|
||||
|
||||
void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
|
||||
cairo_region_t *region);
|
||||
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
|
||||
cairo_region_t *region);
|
||||
|
||||
void meta_surface_actor_update_area (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height);
|
||||
|
||||
void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height);
|
||||
void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);
|
||||
|
@ -378,8 +378,8 @@ texture_tower_create_texture (MetaTextureTower *tower,
|
||||
}
|
||||
|
||||
static void
|
||||
texture_tower_revalidate_fbo (MetaTextureTower *tower,
|
||||
int level)
|
||||
texture_tower_revalidate (MetaTextureTower *tower,
|
||||
int level)
|
||||
{
|
||||
CoglTexture *source_texture = tower->textures[level - 1];
|
||||
int source_texture_width = cogl_texture_get_width (source_texture);
|
||||
@ -425,13 +425,9 @@ texture_tower_revalidate_fbo (MetaTextureTower *tower,
|
||||
(2. * invalid->y2) / source_texture_height);
|
||||
|
||||
cogl_object_unref (pipeline);
|
||||
}
|
||||
|
||||
static void
|
||||
texture_tower_revalidate (MetaTextureTower *tower,
|
||||
int level)
|
||||
{
|
||||
texture_tower_revalidate_fbo (tower, level);
|
||||
tower->invalid[level].x1 = tower->invalid[level].x2 = 0;
|
||||
tower->invalid[level].y1 = tower->invalid[level].y2 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,9 +32,17 @@
|
||||
|
||||
#include "meta-surface-actor.h"
|
||||
#include "meta-surface-actor-x11.h"
|
||||
#include "meta-surface-actor-wayland.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "meta-surface-actor-wayland.h"
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
INITIALLY_FROZEN,
|
||||
DRAWING_FIRST_FRAME,
|
||||
EMITTED_FIRST_FRAME
|
||||
} FirstFrameState;
|
||||
|
||||
struct _MetaWindowActorPrivate
|
||||
{
|
||||
@ -70,7 +78,7 @@ struct _MetaWindowActorPrivate
|
||||
gint64 frame_drawn_time;
|
||||
|
||||
guint repaint_scheduled_id;
|
||||
guint allocation_changed_id;
|
||||
guint size_changed_id;
|
||||
|
||||
/*
|
||||
* These need to be counters rather than flags, since more plugins
|
||||
@ -78,6 +86,7 @@ struct _MetaWindowActorPrivate
|
||||
* might be dubious, but we have to at least handle it correctly.
|
||||
*/
|
||||
gint minimize_in_progress;
|
||||
gint unminimize_in_progress;
|
||||
gint maximize_in_progress;
|
||||
gint unmaximize_in_progress;
|
||||
gint map_in_progress;
|
||||
@ -104,6 +113,7 @@ struct _MetaWindowActorPrivate
|
||||
guint no_shadow : 1;
|
||||
|
||||
guint updates_frozen : 1;
|
||||
guint first_frame_state : 2; /* FirstFrameState */
|
||||
};
|
||||
|
||||
typedef struct _FrameData FrameData;
|
||||
@ -115,6 +125,14 @@ struct _FrameData
|
||||
gint64 frame_drawn_time;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FIRST_FRAME,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_META_WINDOW = 1,
|
||||
@ -181,6 +199,31 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
|
||||
actor_class->paint = meta_window_actor_paint;
|
||||
actor_class->get_paint_volume = meta_window_actor_get_paint_volume;
|
||||
|
||||
/**
|
||||
* MetaWindowActor::first-frame:
|
||||
* @actor: the #MetaWindowActor instance
|
||||
*
|
||||
* The ::first-frame signal will be emitted the first time a frame
|
||||
* of window contents has been drawn by the application and Mutter
|
||||
* has had the chance to drawn that frame to the screen. If the
|
||||
* window starts off initially hidden, obscured, or on on a
|
||||
* different workspace, the ::first-frame signal will be emitted
|
||||
* even though the user doesn't see the contents.
|
||||
*
|
||||
* MetaDisplay::window-created is a good place to connect to this
|
||||
* signal - at that point, the MetaWindowActor for the window
|
||||
* exists, but the window has reliably not yet been drawn.
|
||||
* Connecting to an existing window that has already been drawn to
|
||||
* the screen is not useful.
|
||||
*/
|
||||
signals[FIRST_FRAME] =
|
||||
g_signal_new ("first-frame",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
pspec = g_param_spec_object ("meta-window",
|
||||
"MetaWindow",
|
||||
"The displayed MetaWindow",
|
||||
@ -232,12 +275,11 @@ window_appears_focused_notify (MetaWindow *mw,
|
||||
}
|
||||
|
||||
static void
|
||||
surface_allocation_changed_notify (ClutterActor *actor,
|
||||
const ClutterActorBox *allocation,
|
||||
ClutterAllocationFlags flags,
|
||||
MetaWindowActor *self)
|
||||
surface_size_changed (MetaSurfaceActor *actor,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_window_actor_sync_actor_geometry (self, FALSE);
|
||||
MetaWindowActor *self = META_WINDOW_ACTOR (user_data);
|
||||
|
||||
meta_window_actor_update_shape (self);
|
||||
}
|
||||
|
||||
@ -306,6 +348,9 @@ meta_window_actor_thaw (MetaWindowActor *self)
|
||||
if (priv->freeze_count > 0)
|
||||
return;
|
||||
|
||||
if (priv->first_frame_state == INITIALLY_FROZEN)
|
||||
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
||||
|
||||
if (priv->surface)
|
||||
meta_surface_actor_set_frozen (priv->surface, FALSE);
|
||||
|
||||
@ -326,9 +371,8 @@ set_surface (MetaWindowActor *self,
|
||||
if (priv->surface)
|
||||
{
|
||||
g_signal_handler_disconnect (priv->surface, priv->repaint_scheduled_id);
|
||||
g_signal_handler_disconnect (priv->surface, priv->size_changed_id);
|
||||
priv->repaint_scheduled_id = 0;
|
||||
g_signal_handler_disconnect (priv->surface, priv->allocation_changed_id);
|
||||
priv->allocation_changed_id = 0;
|
||||
clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
||||
g_object_unref (priv->surface);
|
||||
}
|
||||
@ -340,14 +384,17 @@ set_surface (MetaWindowActor *self,
|
||||
g_object_ref_sink (priv->surface);
|
||||
priv->repaint_scheduled_id = g_signal_connect (priv->surface, "repaint-scheduled",
|
||||
G_CALLBACK (surface_repaint_scheduled), self);
|
||||
priv->allocation_changed_id = g_signal_connect (priv->surface, "allocation-changed",
|
||||
G_CALLBACK (surface_allocation_changed_notify), self);
|
||||
priv->size_changed_id = g_signal_connect (priv->surface, "size-changed",
|
||||
G_CALLBACK (surface_size_changed), self);
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
|
||||
|
||||
/* If the previous surface actor was frozen, start out
|
||||
* frozen as well... */
|
||||
meta_surface_actor_set_frozen (priv->surface, priv->freeze_count > 0);
|
||||
|
||||
if (!is_frozen (self) && priv->first_frame_state == INITIALLY_FROZEN)
|
||||
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
||||
|
||||
meta_window_actor_update_shape (self);
|
||||
}
|
||||
}
|
||||
@ -359,9 +406,12 @@ meta_window_actor_update_surface (MetaWindowActor *self)
|
||||
MetaWindow *window = priv->window;
|
||||
MetaSurfaceActor *surface_actor;
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (window->surface)
|
||||
surface_actor = window->surface->surface_actor;
|
||||
else if (!meta_is_wayland_compositor ())
|
||||
else
|
||||
#endif
|
||||
if (!meta_is_wayland_compositor ())
|
||||
surface_actor = meta_surface_actor_x11_new (window);
|
||||
else
|
||||
surface_actor = NULL;
|
||||
@ -551,6 +601,7 @@ meta_window_actor_get_shape_bounds (MetaWindowActor *self,
|
||||
|
||||
cairo_region_get_extents (priv->shape_region, bounds);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (META_IS_SURFACE_ACTOR_WAYLAND (priv->surface))
|
||||
{
|
||||
double scale = priv->surface ?
|
||||
@ -560,6 +611,7 @@ meta_window_actor_get_shape_bounds (MetaWindowActor *self,
|
||||
bounds->width *= scale;
|
||||
bounds->height *= scale;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -667,25 +719,16 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
|
||||
{
|
||||
MetaWindowActor *self = META_WINDOW_ACTOR (actor);
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
cairo_rectangle_int_t unobscured_bounds, bounds;
|
||||
gboolean appears_focused = meta_window_appears_focused (priv->window);
|
||||
ClutterVertex origin;
|
||||
|
||||
/* The paint volume is computed before paint functions are called
|
||||
* so our bounds might not be updated yet. Force an update. */
|
||||
meta_window_actor_handle_updates (self);
|
||||
|
||||
meta_window_actor_get_shape_bounds (self, &bounds);
|
||||
|
||||
if (priv->surface)
|
||||
{
|
||||
if (meta_surface_actor_get_unobscured_bounds (priv->surface, &unobscured_bounds))
|
||||
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
|
||||
}
|
||||
|
||||
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
|
||||
{
|
||||
cairo_rectangle_int_t shadow_bounds;
|
||||
ClutterActorBox shadow_box;
|
||||
|
||||
/* We could compute an full clip region as we do for the window
|
||||
* texture, but the shadow is relatively cheap to draw, and
|
||||
@ -695,16 +738,24 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
|
||||
*/
|
||||
|
||||
meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds);
|
||||
gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
|
||||
shadow_box.x1 = shadow_bounds.x;
|
||||
shadow_box.x2 = shadow_bounds.x + shadow_bounds.width;
|
||||
shadow_box.y1 = shadow_bounds.y;
|
||||
shadow_box.y2 = shadow_bounds.y + shadow_bounds.height;
|
||||
|
||||
clutter_paint_volume_union_box (volume, &shadow_box);
|
||||
}
|
||||
|
||||
origin.x = bounds.x;
|
||||
origin.y = bounds.y;
|
||||
origin.z = 0.0f;
|
||||
clutter_paint_volume_set_origin (volume, &origin);
|
||||
if (priv->surface)
|
||||
{
|
||||
const ClutterPaintVolume *child_volume;
|
||||
|
||||
clutter_paint_volume_set_width (volume, bounds.width);
|
||||
clutter_paint_volume_set_height (volume, bounds.height);
|
||||
child_volume = clutter_actor_get_transformed_paint_volume (CLUTTER_ACTOR (priv->surface), actor);
|
||||
if (!child_volume)
|
||||
return FALSE;
|
||||
|
||||
clutter_paint_volume_union (volume, child_volume);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -814,7 +865,7 @@ meta_window_actor_get_surface (MetaWindowActor *self)
|
||||
gboolean
|
||||
meta_window_actor_is_destroyed (MetaWindowActor *self)
|
||||
{
|
||||
return self->priv->disposed;
|
||||
return self->priv->disposed || self->priv->needs_destroy;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -853,7 +904,7 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
|
||||
outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
if (outputs[i].output_id == window->monitor->output_id && outputs[i].crtc)
|
||||
if (outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc)
|
||||
{
|
||||
refresh_rate = outputs[i].crtc->current_mode->refresh_rate;
|
||||
break;
|
||||
@ -876,7 +927,12 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
gboolean no_delay_frame)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
FrameData *frame = g_slice_new0 (FrameData);
|
||||
FrameData *frame;
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
frame = g_slice_new0 (FrameData);
|
||||
|
||||
priv->needs_frame_drawn = TRUE;
|
||||
|
||||
@ -962,6 +1018,9 @@ start_simple_effect (MetaWindowActor *self,
|
||||
case META_PLUGIN_MINIMIZE:
|
||||
counter = &priv->minimize_in_progress;
|
||||
break;
|
||||
case META_PLUGIN_UNMINIMIZE:
|
||||
counter = &priv->unminimize_in_progress;
|
||||
break;
|
||||
case META_PLUGIN_MAP:
|
||||
counter = &priv->map_in_progress;
|
||||
break;
|
||||
@ -1032,6 +1091,16 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case META_PLUGIN_UNMINIMIZE:
|
||||
{
|
||||
priv->unminimize_in_progress--;
|
||||
if (priv->unminimize_in_progress < 0)
|
||||
{
|
||||
g_warning ("Error in unminimize accounting.");
|
||||
priv->unminimize_in_progress = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case META_PLUGIN_MAP:
|
||||
/*
|
||||
* Make sure that the actor is at the correct place in case
|
||||
@ -1107,7 +1176,6 @@ meta_window_actor_destroy (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaWindow *window = priv->window;
|
||||
MetaCompositor *compositor = priv->compositor;
|
||||
MetaWindowType window_type = meta_window_get_window_type (window);
|
||||
|
||||
meta_window_set_compositor_private (window, NULL);
|
||||
@ -1118,12 +1186,6 @@ meta_window_actor_destroy (MetaWindowActor *self)
|
||||
priv->send_frame_messages_timer = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We remove the window from internal lookup hashes and thus any other
|
||||
* unmap events etc fail
|
||||
*/
|
||||
compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self);
|
||||
|
||||
if (window_type == META_WINDOW_DROPDOWN_MENU ||
|
||||
window_type == META_WINDOW_POPUP_MENU ||
|
||||
window_type == META_WINDOW_TOOLTIP ||
|
||||
@ -1197,8 +1259,7 @@ meta_window_actor_show (MetaWindowActor *self,
|
||||
event = META_PLUGIN_MAP;
|
||||
break;
|
||||
case META_COMP_EFFECT_UNMINIMIZE:
|
||||
/* FIXME: should have META_PLUGIN_UNMINIMIZE */
|
||||
event = META_PLUGIN_MAP;
|
||||
event = META_PLUGIN_UNMINIMIZE;
|
||||
break;
|
||||
case META_COMP_EFFECT_NONE:
|
||||
break;
|
||||
@ -1328,6 +1389,11 @@ meta_window_actor_new (MetaWindow *window)
|
||||
|
||||
meta_window_actor_sync_updates_frozen (self);
|
||||
|
||||
if (is_frozen (self))
|
||||
priv->first_frame_state = INITIALLY_FROZEN;
|
||||
else
|
||||
priv->first_frame_state = DRAWING_FIRST_FRAME;
|
||||
|
||||
/* If a window doesn't start off with updates frozen, we should
|
||||
* we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
|
||||
*/
|
||||
@ -1596,6 +1662,8 @@ build_and_scan_frame_mask (MetaWindowActor *self,
|
||||
cairo_rectangle_int_t *client_area,
|
||||
cairo_region_t *shape_region)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
guchar *mask_data;
|
||||
guint tex_width, tex_height;
|
||||
@ -1658,10 +1726,7 @@ build_and_scan_frame_mask (MetaWindowActor *self,
|
||||
|
||||
if (meta_texture_rectangle_check (paint_tex))
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *context = clutter_backend_get_cogl_context (backend);
|
||||
|
||||
mask_texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (context, tex_width, tex_height));
|
||||
mask_texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (ctx, tex_width, tex_height));
|
||||
cogl_texture_set_components (mask_texture, COGL_TEXTURE_COMPONENTS_A);
|
||||
cogl_texture_set_region (mask_texture,
|
||||
0, 0, /* src_x/y */
|
||||
@ -1673,15 +1738,9 @@ build_and_scan_frame_mask (MetaWindowActor *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note: we don't allow slicing for this texture because we
|
||||
* need to use it with multi-texturing which doesn't support
|
||||
* sliced textures */
|
||||
mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
|
||||
COGL_TEXTURE_NO_SLICING,
|
||||
COGL_PIXEL_FORMAT_A_8,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
stride,
|
||||
mask_data);
|
||||
mask_texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, tex_width, tex_height,
|
||||
COGL_PIXEL_FORMAT_A_8,
|
||||
stride, mask_data, NULL));
|
||||
}
|
||||
|
||||
meta_shaped_texture_set_mask_texture (stex, mask_texture);
|
||||
@ -1849,6 +1908,9 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
GList *l;
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
meta_window_actor_handle_updates (self);
|
||||
|
||||
for (l = priv->frames; l != NULL; l = l->next)
|
||||
@ -1898,6 +1960,9 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
||||
|
||||
priv->repaint_scheduled = FALSE;
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
/* This window had damage, but wasn't actually redrawn because
|
||||
* it is obscured. So we should wait until timer expiration
|
||||
* before sending _NET_WM_FRAME_* messages.
|
||||
@ -1910,6 +1975,12 @@ meta_window_actor_post_paint (MetaWindowActor *self)
|
||||
do_send_frame_drawn (self, priv->frames->data);
|
||||
priv->needs_frame_drawn = FALSE;
|
||||
}
|
||||
|
||||
if (priv->first_frame_state == DRAWING_FIRST_FRAME)
|
||||
{
|
||||
priv->first_frame_state = EMITTED_FIRST_FRAME;
|
||||
g_signal_emit (self, signals[FIRST_FRAME], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1979,6 +2050,9 @@ meta_window_actor_frame_complete (MetaWindowActor *self,
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
GList *l;
|
||||
|
||||
if (meta_window_actor_is_destroyed (self))
|
||||
return;
|
||||
|
||||
for (l = priv->frames; l;)
|
||||
{
|
||||
GList *l_next = l->next;
|
||||
|
@ -31,64 +31,6 @@ static void cullable_iface_init (MetaCullableInterface *iface);
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
|
||||
|
||||
/* Help macros to scale from OpenGL <-1,1> coordinates system to
|
||||
* window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
|
||||
*/
|
||||
#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
||||
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
|
||||
|
||||
/* Check if we're painting the MetaWindowGroup "untransformed". This can
|
||||
* differ from the result of actor_is_untransformed(window_group) if we're
|
||||
* inside a clone paint. The integer translation, if any, is returned.
|
||||
*/
|
||||
static gboolean
|
||||
painting_untransformed (MetaWindowGroup *window_group,
|
||||
int *x_origin,
|
||||
int *y_origin)
|
||||
{
|
||||
CoglMatrix modelview, projection, modelview_projection;
|
||||
ClutterVertex vertices[4];
|
||||
int width, height;
|
||||
float viewport[4];
|
||||
int i;
|
||||
|
||||
cogl_get_modelview_matrix (&modelview);
|
||||
cogl_get_projection_matrix (&projection);
|
||||
|
||||
cogl_matrix_multiply (&modelview_projection,
|
||||
&projection,
|
||||
&modelview);
|
||||
|
||||
meta_screen_get_size (window_group->screen, &width, &height);
|
||||
|
||||
vertices[0].x = 0;
|
||||
vertices[0].y = 0;
|
||||
vertices[0].z = 0;
|
||||
vertices[1].x = width;
|
||||
vertices[1].y = 0;
|
||||
vertices[1].z = 0;
|
||||
vertices[2].x = 0;
|
||||
vertices[2].y = height;
|
||||
vertices[2].z = 0;
|
||||
vertices[3].x = width;
|
||||
vertices[3].y = height;
|
||||
vertices[3].z = 0;
|
||||
|
||||
cogl_get_viewport (viewport);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
float w = 1;
|
||||
cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w);
|
||||
vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w,
|
||||
viewport[2], viewport[0]);
|
||||
vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w,
|
||||
viewport[3], viewport[1]);
|
||||
}
|
||||
|
||||
return meta_actor_vertices_are_untransformed (vertices, width, height, x_origin, y_origin);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_group_cull_out (MetaCullable *cullable,
|
||||
cairo_region_t *unobscured_region,
|
||||
@ -119,10 +61,13 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
int paint_x_offset, paint_y_offset;
|
||||
int paint_x_origin, paint_y_origin;
|
||||
int actor_x_origin, actor_y_origin;
|
||||
int screen_width, screen_height;
|
||||
|
||||
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
|
||||
ClutterActor *stage = clutter_actor_get_stage (actor);
|
||||
|
||||
meta_screen_get_size (window_group->screen, &screen_width, &screen_height);
|
||||
|
||||
/* Normally we expect an actor to be drawn at it's position on the screen.
|
||||
* However, if we're inside the paint of a ClutterClone, that won't be the
|
||||
* case and we need to compensate. We look at the position of the window
|
||||
@ -136,7 +81,7 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
* painting currently, and never worry about how actors are positioned
|
||||
* on the stage.
|
||||
*/
|
||||
if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
|
||||
if (!meta_actor_painting_untransformed (screen_width, screen_height, &paint_x_origin, &paint_y_origin) ||
|
||||
!meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
|
||||
{
|
||||
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
|
||||
|
@ -303,15 +303,16 @@ on_monitors_changed (MetaScreen *screen,
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
MetaRectangle rect;
|
||||
ClutterActor *background;
|
||||
ClutterActor *background_actor;
|
||||
MetaBackground *background;
|
||||
ClutterColor color;
|
||||
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
|
||||
background = meta_background_actor_new ();
|
||||
background_actor = meta_background_actor_new (screen, i);
|
||||
|
||||
clutter_actor_set_position (background, rect.x, rect.y);
|
||||
clutter_actor_set_size (background, rect.width, rect.height);
|
||||
clutter_actor_set_position (background_actor, rect.x, rect.y);
|
||||
clutter_actor_set_size (background_actor, rect.width, rect.height);
|
||||
|
||||
/* Don't use rand() here, mesa calls srand() internally when
|
||||
parsing the driconf XML, but it's nice if the colors are
|
||||
@ -322,9 +323,13 @@ on_monitors_changed (MetaScreen *screen,
|
||||
g_rand_int_range (rand, 0, 255),
|
||||
g_rand_int_range (rand, 0, 255),
|
||||
255);
|
||||
clutter_actor_set_background_color (background, &color);
|
||||
|
||||
clutter_actor_add_child (self->priv->background_group, background);
|
||||
background = meta_background_new (screen);
|
||||
meta_background_set_color (background, &color);
|
||||
meta_background_actor_set_background (META_BACKGROUND_ACTOR (background_actor), background);
|
||||
g_object_unref (background);
|
||||
|
||||
clutter_actor_add_child (self->priv->background_group, background_actor);
|
||||
}
|
||||
|
||||
g_rand_free (rand);
|
||||
|
120
src/core/bell.c
120
src/core/bell.c
@ -69,12 +69,9 @@
|
||||
*
|
||||
* If the configure script found we had no XKB, this does not exist.
|
||||
*/
|
||||
#ifdef HAVE_XKB
|
||||
static void
|
||||
bell_flash_fullscreen (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
bell_flash_fullscreen (MetaDisplay *display)
|
||||
{
|
||||
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||
meta_compositor_flash_screen (display->compositor, display->screen);
|
||||
}
|
||||
|
||||
@ -139,30 +136,17 @@ bell_flash_window_frame (MetaWindow *window)
|
||||
* @display: The display the bell event came in on
|
||||
* @xkb_ev: The bell event we just received
|
||||
*
|
||||
* Flashes the frame of the focussed window. If there is no focussed window,
|
||||
* Flashes the frame of the focused window. If there is no focused window,
|
||||
* flashes the screen.
|
||||
*/
|
||||
static void
|
||||
bell_flash_frame (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
MetaWindow *window)
|
||||
{
|
||||
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
|
||||
MetaWindow *window;
|
||||
|
||||
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
|
||||
if (!window && (display->focus_window))
|
||||
{
|
||||
window = display->focus_window;
|
||||
}
|
||||
if (window && window->frame)
|
||||
{
|
||||
bell_flash_window_frame (window);
|
||||
}
|
||||
else /* revert to fullscreen flash if there's no focussed window */
|
||||
{
|
||||
bell_flash_fullscreen (display, xkb_ev);
|
||||
}
|
||||
bell_flash_window_frame (window);
|
||||
else
|
||||
bell_flash_fullscreen (display);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,69 +156,73 @@ bell_flash_frame (MetaDisplay *display,
|
||||
*
|
||||
* Gives the user some kind of visual bell substitute, in response to a
|
||||
* bell event. What this is depends on the "visual bell type" pref.
|
||||
*
|
||||
* If the configure script found we had no XKB, this does not exist.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bug: This should be merged with meta_bell_notify().
|
||||
*/
|
||||
static void
|
||||
bell_visual_notify (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
MetaWindow *window)
|
||||
{
|
||||
switch (meta_prefs_get_visual_bell_type ())
|
||||
{
|
||||
case G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH:
|
||||
bell_flash_fullscreen (display, xkb_ev);
|
||||
bell_flash_fullscreen (display);
|
||||
break;
|
||||
case G_DESKTOP_VISUAL_BELL_FRAME_FLASH:
|
||||
bell_flash_frame (display, xkb_ev); /* does nothing yet */
|
||||
bell_flash_frame (display, window);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bell_audible_notify (MetaDisplay *display,
|
||||
MetaWindow *window)
|
||||
{
|
||||
#ifdef HAVE_LIBCANBERRA
|
||||
ca_proplist *p;
|
||||
int res;
|
||||
|
||||
ca_proplist_create (&p);
|
||||
ca_proplist_sets (p, CA_PROP_EVENT_ID, "bell-window-system");
|
||||
ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, _("Bell event"));
|
||||
ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
|
||||
|
||||
if (window)
|
||||
{
|
||||
ca_proplist_sets (p, CA_PROP_WINDOW_NAME, window->title);
|
||||
ca_proplist_setf (p, CA_PROP_WINDOW_X11_XID, "%lu", (unsigned long)window->xwindow);
|
||||
ca_proplist_sets (p, CA_PROP_APPLICATION_NAME, window->res_name);
|
||||
ca_proplist_setf (p, CA_PROP_APPLICATION_PROCESS_ID, "%d", window->net_wm_pid);
|
||||
}
|
||||
|
||||
res = ca_context_play_full (ca_gtk_context_get (), 1, p, NULL, NULL);
|
||||
|
||||
ca_proplist_destroy (p);
|
||||
|
||||
return res == CA_SUCCESS || res == CA_ERROR_DISABLED;
|
||||
#endif /* HAVE_LIBCANBERRA */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_bell_notify (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
{
|
||||
MetaWindow *window;
|
||||
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
|
||||
|
||||
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
|
||||
if (!window && display->focus_window && display->focus_window->frame)
|
||||
window = display->focus_window;
|
||||
|
||||
/* flash something */
|
||||
if (meta_prefs_get_visual_bell ())
|
||||
bell_visual_notify (display, xkb_ev);
|
||||
bell_visual_notify (display, window);
|
||||
|
||||
#ifdef HAVE_LIBCANBERRA
|
||||
if (meta_prefs_bell_is_audible ())
|
||||
{
|
||||
ca_proplist *p;
|
||||
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
|
||||
MetaWindow *window;
|
||||
int res;
|
||||
|
||||
ca_proplist_create (&p);
|
||||
ca_proplist_sets (p, CA_PROP_EVENT_ID, "bell-window-system");
|
||||
ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, _("Bell event"));
|
||||
ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
|
||||
|
||||
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
|
||||
if (!window && (display->focus_window) && (display->focus_window->frame))
|
||||
window = display->focus_window;
|
||||
|
||||
if (window)
|
||||
if (!bell_audible_notify (display, window))
|
||||
{
|
||||
ca_proplist_sets (p, CA_PROP_WINDOW_NAME, window->title);
|
||||
ca_proplist_setf (p, CA_PROP_WINDOW_X11_XID, "%lu", (unsigned long)window->xwindow);
|
||||
ca_proplist_sets (p, CA_PROP_APPLICATION_NAME, window->res_name);
|
||||
ca_proplist_setf (p, CA_PROP_APPLICATION_PROCESS_ID, "%d", window->net_wm_pid);
|
||||
}
|
||||
|
||||
/* First, we try to play a real sound ... */
|
||||
res = ca_context_play_full (ca_gtk_context_get (), 1, p, NULL, NULL);
|
||||
|
||||
ca_proplist_destroy (p);
|
||||
|
||||
if (res != CA_SUCCESS && res != CA_ERROR_DISABLED)
|
||||
{
|
||||
/* ...and in case that failed we use the classic X11 bell. */
|
||||
/* Force a classic bell if the libcanberra bell failed. */
|
||||
XkbForceDeviceBell (display->xdisplay,
|
||||
xkb_bell_event->device,
|
||||
xkb_bell_event->bell_class,
|
||||
@ -242,14 +230,11 @@ meta_bell_notify (MetaDisplay *display,
|
||||
xkb_bell_event->percent);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBCANBERRA */
|
||||
}
|
||||
#endif /* HAVE_XKB */
|
||||
|
||||
void
|
||||
meta_bell_set_audible (MetaDisplay *display, gboolean audible)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
#ifdef HAVE_LIBCANBERRA
|
||||
/* When we are playing sounds using libcanberra support, we handle the
|
||||
* bell whether its an audible bell or a visible bell */
|
||||
@ -262,13 +247,11 @@ meta_bell_set_audible (MetaDisplay *display, gboolean audible)
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
enable_system_bell ? XkbAudibleBellMask : 0);
|
||||
#endif /* HAVE_XKB */
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_bell_init (MetaDisplay *display)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
int xkb_base_error_type, xkb_opcode;
|
||||
|
||||
if (!XkbQueryExtension (display->xdisplay, &xkb_opcode,
|
||||
@ -298,20 +281,17 @@ meta_bell_init (MetaDisplay *display)
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_bell_shutdown (MetaDisplay *display)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
/* TODO: persist initial bell state in display, reset here */
|
||||
XkbChangeEnabledControls (display->xdisplay,
|
||||
XkbUseCoreKbd,
|
||||
XkbAudibleBellMask,
|
||||
XkbAudibleBellMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,13 +18,10 @@
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#ifdef HAVE_XKB
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
#include "display-private.h"
|
||||
#include "frame.h"
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
/**
|
||||
* meta_bell_notify:
|
||||
* @display: The display the bell event came in on
|
||||
@ -37,7 +34,6 @@
|
||||
* If the configure script found we had no XKB, this does not exist.
|
||||
*/
|
||||
void meta_bell_notify (MetaDisplay *display, XkbAnyEvent *xkb_ev);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* meta_bell_set_audible:
|
||||
@ -61,12 +57,6 @@ void meta_bell_set_audible (MetaDisplay *display, gboolean audible);
|
||||
* to send us bell notifications, and then also switching
|
||||
* off the audible bell if we're using a visual one ourselves.
|
||||
*
|
||||
* Unlike most X extensions we use, we only initialise XKB here
|
||||
* (rather than in main()). It's possible that XKB is not
|
||||
* installed at all, but if that was known at build time
|
||||
* we will have HAVE_XKB undefined, which will cause this
|
||||
* function to be a no-op.
|
||||
*
|
||||
* \bug There is a line of code that's never run that tells
|
||||
* XKB to reset the bell status after we quit. Bill H said
|
||||
* (<http://bugzilla.gnome.org/show_bug.cgi?id=99886#c12>)
|
||||
|
@ -495,46 +495,5 @@ meta_core_set_screen_cursor (Display *xdisplay,
|
||||
void
|
||||
meta_invalidate_default_icons (void)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
GSList *windows;
|
||||
GSList *l;
|
||||
|
||||
if (display == NULL)
|
||||
return; /* We can validly be called before the display is opened. */
|
||||
|
||||
windows = meta_display_list_windows (display, META_LIST_DEFAULT);
|
||||
for (l = windows; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWindow *window = (MetaWindow*)l->data;
|
||||
|
||||
if (window->icon_cache.origin == USING_FALLBACK_ICON)
|
||||
{
|
||||
meta_icon_cache_free (&(window->icon_cache));
|
||||
meta_window_update_icon_now (window);
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free (windows);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_add_old_event_mask (Display *xdisplay,
|
||||
Window xwindow,
|
||||
XIEventMask *mask)
|
||||
{
|
||||
XIEventMask *prev;
|
||||
gint n_masks, i, j;
|
||||
|
||||
prev = XIGetSelectedEvents (xdisplay, xwindow, &n_masks);
|
||||
|
||||
for (i = 0; i < n_masks; i++)
|
||||
{
|
||||
if (prev[i].deviceid != XIAllMasterDevices)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < MIN (mask->mask_len, prev[i].mask_len); j++)
|
||||
mask->mask[j] |= prev[i].mask[j];
|
||||
}
|
||||
|
||||
XFree (prev);
|
||||
/* XXX: Actually invalidate the icons when they're used. */
|
||||
}
|
||||
|
@ -169,8 +169,4 @@ void meta_core_set_screen_cursor (Display *xdisplay,
|
||||
|
||||
void meta_invalidate_default_icons (void);
|
||||
|
||||
void meta_core_add_old_event_mask (Display *xdisplay,
|
||||
Window xwindow,
|
||||
XIEventMask *mask);
|
||||
|
||||
#endif
|
||||
|
@ -37,8 +37,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
|
||||
static void
|
||||
dialog_exited (GPid pid, int status, gpointer user_data)
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <meta/boxes.h>
|
||||
#include <meta/display.h>
|
||||
#include "keybindings-private.h"
|
||||
#include "meta-gesture-tracker-private.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/barrier.h>
|
||||
#include <clutter/clutter.h>
|
||||
@ -78,6 +79,28 @@ typedef enum {
|
||||
META_TILE_MAXIMIZED
|
||||
} MetaTileMode;
|
||||
|
||||
typedef enum {
|
||||
/* Normal interaction where you're interacting with windows.
|
||||
* Events go to windows normally. */
|
||||
META_EVENT_ROUTE_NORMAL,
|
||||
|
||||
/* In a compositor grab operation. All events go to the
|
||||
* compositor plugin. */
|
||||
META_EVENT_ROUTE_COMPOSITOR_GRAB,
|
||||
|
||||
/* A Wayland application has a popup open. All events go to
|
||||
* the Wayland application. */
|
||||
META_EVENT_ROUTE_WAYLAND_POPUP,
|
||||
|
||||
/* In a window operation like moving or resizing. All events
|
||||
* goes to MetaWindow, but not to the actual client window. */
|
||||
META_EVENT_ROUTE_WINDOW_OP,
|
||||
} MetaEventRoute;
|
||||
|
||||
typedef gboolean (*MetaAlarmFilter) (MetaDisplay *display,
|
||||
XSyncAlarmNotifyEvent *event,
|
||||
gpointer data);
|
||||
|
||||
struct _MetaDisplay
|
||||
{
|
||||
GObject parent_instance;
|
||||
@ -143,10 +166,9 @@ struct _MetaDisplay
|
||||
/*< private-ish >*/
|
||||
MetaScreen *screen;
|
||||
GHashTable *xids;
|
||||
GHashTable *stamps;
|
||||
GHashTable *wayland_windows;
|
||||
|
||||
int server_grab_count;
|
||||
|
||||
/* serials of leave/unmap events that may
|
||||
* correspond to an enter event we should
|
||||
* ignore
|
||||
@ -175,8 +197,8 @@ struct _MetaDisplay
|
||||
guint autoraise_timeout_id;
|
||||
MetaWindow* autoraise_window;
|
||||
|
||||
/* Alt+click button grabs */
|
||||
ClutterModifierType window_grab_modifiers;
|
||||
/* Event routing */
|
||||
MetaEventRoute event_route;
|
||||
|
||||
/* current window operation */
|
||||
MetaGrabOp grab_op;
|
||||
@ -201,34 +223,17 @@ struct _MetaDisplay
|
||||
GTimeVal grab_last_moveresize_time;
|
||||
MetaEdgeResistanceData *grab_edge_resistance_data;
|
||||
unsigned int grab_last_user_action_was_snap;
|
||||
guint32 grab_timestamp;
|
||||
|
||||
/* we use property updates as sentinels for certain window focus events
|
||||
* to avoid some race conditions on EnterNotify events
|
||||
*/
|
||||
int sentinel_counter;
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
int xkb_base_event_type;
|
||||
guint32 last_bell_time;
|
||||
#endif
|
||||
int grab_resize_timeout_id;
|
||||
|
||||
/* Keybindings stuff */
|
||||
GHashTable *key_bindings;
|
||||
GHashTable *key_bindings_index;
|
||||
int min_keycode;
|
||||
int max_keycode;
|
||||
KeySym *keymap;
|
||||
int keysyms_per_keycode;
|
||||
unsigned int ignored_modifier_mask;
|
||||
unsigned int hyper_mask;
|
||||
unsigned int super_mask;
|
||||
unsigned int meta_mask;
|
||||
MetaKeyCombo overlay_key_combo;
|
||||
gboolean overlay_key_only_pressed;
|
||||
MetaKeyCombo *iso_next_group_combos;
|
||||
int n_iso_next_group_combos;
|
||||
MetaKeyBindingManager key_binding_manager;
|
||||
|
||||
/* Monitor cache */
|
||||
unsigned int monitor_cache_invalidated : 1;
|
||||
@ -253,6 +258,12 @@ struct _MetaDisplay
|
||||
/* Managed by compositor.c */
|
||||
MetaCompositor *compositor;
|
||||
|
||||
MetaGestureTracker *gesture_tracker;
|
||||
ClutterEventSequence *pointer_emulating_sequence;
|
||||
|
||||
MetaAlarmFilter alarm_filter;
|
||||
gpointer alarm_filter_data;
|
||||
|
||||
int composite_event_base;
|
||||
int composite_error_base;
|
||||
int composite_major_version;
|
||||
@ -311,8 +322,6 @@ struct _MetaDisplayClass
|
||||
gboolean meta_display_open (void);
|
||||
void meta_display_close (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
void meta_display_grab (MetaDisplay *display);
|
||||
void meta_display_ungrab (MetaDisplay *display);
|
||||
|
||||
void meta_display_unmanage_windows_for_screen (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
@ -333,6 +342,29 @@ void meta_display_register_x_window (MetaDisplay *display,
|
||||
void meta_display_unregister_x_window (MetaDisplay *display,
|
||||
Window xwindow);
|
||||
|
||||
/* Each MetaWindow is uniquely identified by a 64-bit "stamp"; unlike a
|
||||
* a MetaWindow *, a stamp will never be recycled
|
||||
*/
|
||||
MetaWindow* meta_display_lookup_stamp (MetaDisplay *display,
|
||||
guint64 stamp);
|
||||
void meta_display_register_stamp (MetaDisplay *display,
|
||||
guint64 *stampp,
|
||||
MetaWindow *window);
|
||||
void meta_display_unregister_stamp (MetaDisplay *display,
|
||||
guint64 stamp);
|
||||
|
||||
/* A "stack id" is a XID or a stamp */
|
||||
|
||||
#define META_STACK_ID_IS_X11(id) ((id) < G_GUINT64_CONSTANT(0x100000000))
|
||||
MetaWindow* meta_display_lookup_stack_id (MetaDisplay *display,
|
||||
guint64 stack_id);
|
||||
|
||||
/* for debug logging only; returns a human-description of the stack
|
||||
* ID - a small number of buffers are recycled, so the result must
|
||||
* be used immediately or copied */
|
||||
const char *meta_display_describe_stack_id (MetaDisplay *display,
|
||||
guint64 stack_id);
|
||||
|
||||
void meta_display_register_wayland_window (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
void meta_display_unregister_wayland_window (MetaDisplay *display,
|
||||
@ -397,14 +429,8 @@ int meta_resize_gravity_from_grab_op (MetaGrabOp op);
|
||||
|
||||
gboolean meta_grab_op_is_moving (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_resizing (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_moving_or_resizing (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_mouse (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_keyboard (MetaGrabOp op);
|
||||
gboolean meta_grab_op_should_block_wayland (MetaGrabOp op);
|
||||
|
||||
void meta_display_devirtualize_modifiers (MetaDisplay *display,
|
||||
MetaVirtualModifier modifiers,
|
||||
unsigned int *mask);
|
||||
|
||||
void meta_display_increment_focus_sentinel (MetaDisplay *display);
|
||||
void meta_display_decrement_focus_sentinel (MetaDisplay *display);
|
||||
@ -442,4 +468,24 @@ void meta_display_sanity_check_timestamps (MetaDisplay *display,
|
||||
gboolean meta_display_timestamp_too_old (MetaDisplay *display,
|
||||
guint32 *timestamp);
|
||||
|
||||
void meta_display_remove_pending_pings_for_window (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
|
||||
MetaGestureTracker * meta_display_get_gesture_tracker (MetaDisplay *display);
|
||||
|
||||
gboolean meta_display_show_restart_message (MetaDisplay *display,
|
||||
const char *message);
|
||||
gboolean meta_display_request_restart (MetaDisplay *display);
|
||||
|
||||
void meta_restart_init (void);
|
||||
void meta_restart_finish (void);
|
||||
|
||||
void meta_display_cancel_touch (MetaDisplay *display);
|
||||
|
||||
gboolean meta_display_windows_are_interactable (MetaDisplay *display);
|
||||
|
||||
void meta_display_set_alarm_filter (MetaDisplay *display,
|
||||
MetaAlarmFilter filter,
|
||||
gpointer data);
|
||||
|
||||
#endif
|
||||
|
1115
src/core/display.c
1115
src/core/display.c
File diff suppressed because it is too large
Load Diff
@ -23,9 +23,10 @@
|
||||
#include "config.h"
|
||||
#include "events.h"
|
||||
|
||||
#include <meta/meta-backend.h>
|
||||
|
||||
#include "display-private.h"
|
||||
#include "window-private.h"
|
||||
#include "backends/meta-backend.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
@ -33,34 +34,45 @@
|
||||
#include "backends/native/meta-idle-monitor-native.h"
|
||||
#endif
|
||||
|
||||
#include "x11/events.h"
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#endif
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
static MetaWindow *
|
||||
get_window_for_event (MetaDisplay *display,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
ClutterActor *source;
|
||||
|
||||
if (display->grab_op != META_GRAB_OP_NONE)
|
||||
return display->grab_window;
|
||||
|
||||
/* Always use the key focused window for key events. */
|
||||
switch (event->type)
|
||||
switch (display->event_route)
|
||||
{
|
||||
case CLUTTER_KEY_PRESS:
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
return display->focus_window;
|
||||
case META_EVENT_ROUTE_NORMAL:
|
||||
{
|
||||
ClutterActor *source;
|
||||
|
||||
/* Always use the key focused window for key events. */
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_KEY_PRESS:
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
return display->focus_window;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
source = clutter_event_get_source (event);
|
||||
if (META_IS_SURFACE_ACTOR (source))
|
||||
return meta_surface_actor_get_window (META_SURFACE_ACTOR (source));
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
case META_EVENT_ROUTE_WAYLAND_POPUP:
|
||||
case META_EVENT_ROUTE_WINDOW_OP:
|
||||
case META_EVENT_ROUTE_COMPOSITOR_GRAB:
|
||||
return display->grab_window;
|
||||
default:
|
||||
break;
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
source = clutter_event_get_source (event);
|
||||
if (META_IS_SURFACE_ACTOR (source))
|
||||
return meta_surface_actor_get_window (META_SURFACE_ACTOR (source));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -99,19 +111,88 @@ handle_idletime_for_event (const ClutterEvent *event)
|
||||
#endif /* HAVE_NATIVE_BACKEND */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sequence_is_pointer_emulated (MetaDisplay *display,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
ClutterEventSequence *sequence;
|
||||
|
||||
sequence = clutter_event_get_event_sequence (event);
|
||||
|
||||
if (!sequence)
|
||||
return FALSE;
|
||||
|
||||
if (clutter_event_is_pointer_emulated (event))
|
||||
return TRUE;
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
|
||||
/* When using Clutter's native input backend there is no concept of
|
||||
* pointer emulating sequence, we still must make up our own to be
|
||||
* able to implement single-touch (hence pointer alike) behavior.
|
||||
*
|
||||
* This is implemented similarly to X11, where only the first touch
|
||||
* on screen gets the "pointer emulated" flag, and it won't get assigned
|
||||
* to another sequence until the next first touch on an idle touchscreen.
|
||||
*/
|
||||
if (META_IS_BACKEND_NATIVE (backend))
|
||||
{
|
||||
MetaGestureTracker *tracker;
|
||||
|
||||
tracker = meta_display_get_gesture_tracker (display);
|
||||
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN &&
|
||||
meta_gesture_tracker_get_n_current_touches (tracker) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* HAVE_NATIVE_BACKEND */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_display_update_pointer_emulating_sequence (MetaDisplay *display,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
ClutterEventSequence *sequence;
|
||||
|
||||
sequence = clutter_event_get_event_sequence (event);
|
||||
|
||||
if (event->type == CLUTTER_TOUCH_BEGIN &&
|
||||
!display->pointer_emulating_sequence &&
|
||||
sequence_is_pointer_emulated (display, event))
|
||||
display->pointer_emulating_sequence = sequence;
|
||||
else if (event->type == CLUTTER_TOUCH_END &&
|
||||
display->pointer_emulating_sequence == sequence)
|
||||
display->pointer_emulating_sequence = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_display_handle_event (MetaDisplay *display,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaWindow *window;
|
||||
gboolean bypass_clutter = FALSE, bypass_wayland = FALSE;
|
||||
MetaWaylandCompositor *compositor = NULL;
|
||||
gboolean bypass_clutter = FALSE;
|
||||
G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
|
||||
MetaGestureTracker *tracker;
|
||||
|
||||
meta_display_update_pointer_emulating_sequence (display, event);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
MetaWaylandCompositor *compositor = NULL;
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
meta_wayland_compositor_update (compositor, event);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
|
||||
{
|
||||
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
|
||||
meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y);
|
||||
}
|
||||
|
||||
handle_idletime_for_event (event);
|
||||
|
||||
@ -120,7 +201,9 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
display->current_time = event->any.time;
|
||||
|
||||
if (window && !window->override_redirect &&
|
||||
(event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS))
|
||||
(event->type == CLUTTER_KEY_PRESS ||
|
||||
event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_TOUCH_BEGIN))
|
||||
{
|
||||
if (CurrentTime == display->current_time)
|
||||
{
|
||||
@ -139,8 +222,15 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
if (display->grab_window == window &&
|
||||
meta_grab_op_is_moving_or_resizing (display->grab_op))
|
||||
tracker = meta_display_get_gesture_tracker (display);
|
||||
|
||||
if (meta_gesture_tracker_handle_event (tracker, event))
|
||||
{
|
||||
bypass_wayland = bypass_clutter = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
|
||||
{
|
||||
if (meta_window_handle_mouse_grab_op_event (window, event))
|
||||
{
|
||||
@ -165,29 +255,42 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
|
||||
if (window)
|
||||
{
|
||||
/* Swallow all events on windows that come our way. */
|
||||
bypass_clutter = TRUE;
|
||||
|
||||
/* Under X11, we have a Sync grab and in order to send it back to
|
||||
* clients, we have to explicitly replay it.
|
||||
*
|
||||
* Under Wayland, we retrieve all events and we have to make sure
|
||||
* to filter them out from Wayland clients.
|
||||
*/
|
||||
if (meta_window_handle_ungrabbed_event (window, event))
|
||||
if (!clutter_event_get_event_sequence (event))
|
||||
{
|
||||
/* Swallow all non-touch events on windows that come our way.
|
||||
* Touch events that reach here aren't yet in an accepted state,
|
||||
* so Clutter must see them to maybe trigger gestures into
|
||||
* recognition.
|
||||
*/
|
||||
bypass_clutter = TRUE;
|
||||
}
|
||||
|
||||
meta_window_handle_ungrabbed_event (window, event);
|
||||
|
||||
/* This might start a grab op. If it does, then filter out the
|
||||
* event, and if it doesn't, replay the event to release our
|
||||
* own sync grab. */
|
||||
|
||||
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
|
||||
{
|
||||
bypass_clutter = TRUE;
|
||||
bypass_wayland = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
if (META_IS_BACKEND_X11 (backend))
|
||||
/* Only replay button press events, since that's where we
|
||||
* have the synchronous grab. */
|
||||
if (event->type == CLUTTER_BUTTON_PRESS)
|
||||
{
|
||||
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
||||
meta_verbose ("Allowing events time %u\n",
|
||||
(unsigned int)event->button.time);
|
||||
XIAllowEvents (xdisplay, clutter_event_get_device_id (event),
|
||||
XIReplayDevice, event->button.time);
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
if (META_IS_BACKEND_X11 (backend))
|
||||
{
|
||||
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
||||
meta_verbose ("Allowing events time %u\n",
|
||||
(unsigned int)event->button.time);
|
||||
XIAllowEvents (xdisplay, clutter_event_get_device_id (event),
|
||||
XIReplayDevice, event->button.time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,18 +299,20 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
|
||||
out:
|
||||
/* If the compositor has a grab, don't pass that through to Wayland */
|
||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||
if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB)
|
||||
bypass_wayland = TRUE;
|
||||
|
||||
/* If a Wayland client has a grab, don't pass that through to Clutter */
|
||||
if (display->grab_op == META_GRAB_OP_WAYLAND_POPUP)
|
||||
if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP)
|
||||
bypass_clutter = TRUE;
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (compositor && !bypass_wayland)
|
||||
{
|
||||
if (meta_wayland_compositor_handle_event (compositor, event))
|
||||
bypass_clutter = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
display->current_time = CurrentTime;
|
||||
return bypass_clutter;
|
||||
@ -225,7 +330,6 @@ event_callback (const ClutterEvent *event,
|
||||
void
|
||||
meta_display_init_events (MetaDisplay *display)
|
||||
{
|
||||
meta_display_init_events_x11 (display);
|
||||
display->clutter_event_filter = clutter_event_add_filter (NULL,
|
||||
event_callback,
|
||||
NULL,
|
||||
@ -235,7 +339,6 @@ meta_display_init_events (MetaDisplay *display)
|
||||
void
|
||||
meta_display_free_events (MetaDisplay *display)
|
||||
{
|
||||
meta_display_free_events_x11 (display);
|
||||
clutter_event_remove_filter (display->clutter_event_filter);
|
||||
display->clutter_event_filter = 0;
|
||||
}
|
||||
|
@ -26,14 +26,11 @@
|
||||
#include "bell.h"
|
||||
#include <meta/errors.h>
|
||||
#include "keybindings-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
|
||||
#define EVENT_MASK (SubstructureRedirectMask | \
|
||||
StructureNotifyMask | SubstructureNotifyMask | \
|
||||
ExposureMask | \
|
||||
ButtonPressMask | ButtonReleaseMask | \
|
||||
PointerMotionMask | PointerMotionHintMask | \
|
||||
EnterWindowMask | LeaveWindowMask | \
|
||||
FocusChangeMask)
|
||||
ExposureMask | FocusChangeMask)
|
||||
|
||||
void
|
||||
meta_window_ensure_frame (MetaWindow *window)
|
||||
@ -42,7 +39,6 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
XSetWindowAttributes attrs;
|
||||
Visual *visual;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame)
|
||||
return;
|
||||
@ -98,10 +94,8 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
frame->rect.height,
|
||||
frame->window->screen->number,
|
||||
&create_serial);
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = frame->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
&stack_window,
|
||||
frame->xwindow,
|
||||
create_serial);
|
||||
|
||||
meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
|
||||
@ -109,6 +103,19 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
XChangeWindowAttributes (window->display->xdisplay,
|
||||
frame->xwindow, CWEventMask, &attrs);
|
||||
|
||||
{
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
|
||||
XISelectEvents (window->display->xdisplay, frame->xwindow, &mask, 1);
|
||||
}
|
||||
|
||||
meta_display_register_x_window (window->display, &frame->xwindow, window);
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
@ -122,9 +129,8 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
window->unmaps_pending += 1;
|
||||
}
|
||||
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_remove (window->screen->stack_tracker,
|
||||
&stack_window,
|
||||
window->xwindow,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
@ -141,7 +147,6 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
* style and background.
|
||||
*/
|
||||
meta_ui_update_frame_style (window->screen->ui, frame->xwindow);
|
||||
meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow);
|
||||
|
||||
if (window->title)
|
||||
meta_ui_set_frame_title (window->screen->ui,
|
||||
@ -150,10 +155,16 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
|
||||
meta_ui_map_frame (frame->window->screen->ui, frame->xwindow);
|
||||
|
||||
/* Since the backend takes keygrabs on another connection, make sure
|
||||
* to sync the GTK+ connection to ensure that the frame window has
|
||||
* been created on the server at this point. */
|
||||
XSync (window->display->xdisplay, False);
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
if (META_IS_BACKEND_X11 (backend))
|
||||
{
|
||||
/* Since the backend takes keygrabs on another connection, make sure
|
||||
* to sync the GTK+ connection to ensure that the frame window has
|
||||
* been created on the server at this point. */
|
||||
XSync (window->display->xdisplay, False);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move keybindings to frame instead of window */
|
||||
meta_window_grab_keys (window);
|
||||
@ -164,7 +175,6 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
{
|
||||
MetaFrame *frame;
|
||||
MetaFrameBorders borders;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame == NULL)
|
||||
return;
|
||||
@ -191,10 +201,8 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
|
||||
window->unmaps_pending += 1;
|
||||
}
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
&stack_window,
|
||||
window->xwindow,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
@ -356,15 +364,6 @@ meta_frame_sync_to_window (MetaFrame *frame,
|
||||
frame->rect.x + frame->rect.width,
|
||||
frame->rect.y + frame->rect.height);
|
||||
|
||||
/* set bg to none to avoid flicker */
|
||||
if (need_resize)
|
||||
{
|
||||
meta_ui_unflicker_frame_bg (frame->window->screen->ui,
|
||||
frame->xwindow,
|
||||
frame->rect.width,
|
||||
frame->rect.height);
|
||||
}
|
||||
|
||||
meta_ui_move_resize_frame (frame->window->screen->ui,
|
||||
frame->xwindow,
|
||||
frame->rect.x,
|
||||
@ -374,9 +373,6 @@ meta_frame_sync_to_window (MetaFrame *frame,
|
||||
|
||||
if (need_resize)
|
||||
{
|
||||
meta_ui_reset_frame_bg (frame->window->screen->ui,
|
||||
frame->xwindow);
|
||||
|
||||
/* If we're interactively resizing the frame, repaint
|
||||
* it immediately so we don't start to lag.
|
||||
*/
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <meta/keybindings.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
typedef struct _MetaKeyHandler MetaKeyHandler;
|
||||
struct _MetaKeyHandler
|
||||
@ -80,9 +81,6 @@ typedef struct
|
||||
*/
|
||||
GSList *combos;
|
||||
|
||||
/* for keybindings that can have shift or not like Alt+Tab */
|
||||
gboolean add_shift:1;
|
||||
|
||||
/* for keybindings that apply only to a window */
|
||||
gboolean per_window:1;
|
||||
|
||||
@ -90,6 +88,23 @@ typedef struct
|
||||
gboolean builtin:1;
|
||||
} MetaKeyPref;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GHashTable *key_bindings;
|
||||
GHashTable *key_bindings_index;
|
||||
xkb_mod_mask_t ignored_modifier_mask;
|
||||
xkb_mod_mask_t hyper_mask;
|
||||
xkb_mod_mask_t super_mask;
|
||||
xkb_mod_mask_t meta_mask;
|
||||
MetaKeyCombo overlay_key_combo;
|
||||
gboolean overlay_key_only_pressed;
|
||||
MetaKeyCombo *iso_next_group_combos;
|
||||
int n_iso_next_group_combos;
|
||||
|
||||
/* Alt+click button grabs */
|
||||
ClutterModifierType window_grab_modifiers;
|
||||
} MetaKeyBindingManager;
|
||||
|
||||
void meta_display_init_keys (MetaDisplay *display);
|
||||
void meta_display_shutdown_keys (MetaDisplay *display);
|
||||
void meta_screen_grab_keys (MetaScreen *screen);
|
||||
@ -103,8 +118,8 @@ void meta_window_ungrab_all_keys (MetaWindow *window,
|
||||
gboolean meta_keybindings_process_event (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
const ClutterEvent *event);
|
||||
void meta_display_process_mapping_event (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
|
||||
ClutterModifierType meta_display_get_window_grab_modifiers (MetaDisplay *display);
|
||||
|
||||
gboolean meta_prefs_add_keybinding (const char *name,
|
||||
GSettings *settings,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -52,6 +52,7 @@
|
||||
#include "ui.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/compositor.h>
|
||||
#include <meta/meta-backend.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib-unix.h>
|
||||
@ -77,8 +78,9 @@
|
||||
|
||||
#include "x11/session.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "wayland/meta-wayland.h"
|
||||
#include "backends/meta-backend.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The exit code we'll return to our parent process when we eventually die.
|
||||
@ -94,26 +96,6 @@ static GMainLoop *meta_main_loop = NULL;
|
||||
static void prefs_changed_callback (MetaPreference pref,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* log_handler:
|
||||
* @log_domain: the domain the error occurred in (we ignore this)
|
||||
* @log_level: the log level so that we can filter out less
|
||||
* important messages
|
||||
* @message: the message to log
|
||||
* @user_data: arbitrary data (we ignore this)
|
||||
*
|
||||
* Prints log messages. If Mutter was compiled with backtrace support,
|
||||
* also prints a backtrace (see meta_print_backtrace()).
|
||||
*/
|
||||
static void
|
||||
log_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_warning ("Log level %d: %s\n", log_level, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_print_compilation_info:
|
||||
*
|
||||
@ -180,7 +162,9 @@ static gchar *opt_client_id;
|
||||
static gboolean opt_replace_wm;
|
||||
static gboolean opt_disable_sm;
|
||||
static gboolean opt_sync;
|
||||
#ifdef HAVE_WAYLAND
|
||||
static gboolean opt_wayland;
|
||||
#endif
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
static gboolean opt_display_server;
|
||||
#endif
|
||||
@ -221,12 +205,14 @@ static GOptionEntry meta_options[] = {
|
||||
N_("Make X calls synchronous"),
|
||||
NULL
|
||||
},
|
||||
#ifdef HAVE_WAYLAND
|
||||
{
|
||||
"wayland", 0, 0, G_OPTION_ARG_NONE,
|
||||
&opt_wayland,
|
||||
N_("Run as a wayland compositor"),
|
||||
NULL
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
{
|
||||
"display-server", 0, 0, G_OPTION_ARG_NONE,
|
||||
@ -291,8 +277,10 @@ meta_finalize (void)
|
||||
meta_display_close (display,
|
||||
CurrentTime); /* I doubt correct timestamps matter here */
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_wayland_finalize ();
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -314,7 +302,6 @@ meta_init (void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigset_t empty_mask;
|
||||
ClutterSettings *clutter_settings;
|
||||
|
||||
sigemptyset (&empty_mask);
|
||||
act.sa_handler = SIG_IGN;
|
||||
@ -339,9 +326,13 @@ meta_init (void)
|
||||
#if defined(CLUTTER_WINDOWING_EGL) && defined(HAVE_NATIVE_BACKEND)
|
||||
if (opt_display_server)
|
||||
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
|
||||
else
|
||||
#endif
|
||||
clutter_set_windowing_backend (CLUTTER_WINDOWING_X11);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
meta_set_is_wayland_compositor (opt_wayland);
|
||||
#endif
|
||||
|
||||
if (g_get_home_dir ())
|
||||
if (chdir (g_get_home_dir ()) < 0)
|
||||
@ -354,15 +345,24 @@ meta_init (void)
|
||||
g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* NB: When running as a hybrid wayland compositor we run our own headless X
|
||||
* server so the user can't control the X display to connect too. */
|
||||
meta_wayland_init ();
|
||||
}
|
||||
else
|
||||
meta_wayland_pre_clutter_init ();
|
||||
#endif
|
||||
|
||||
/* NB: When running as a hybrid wayland compositor we run our own headless X
|
||||
* server so the user can't control the X display to connect too. */
|
||||
if (!meta_is_wayland_compositor ())
|
||||
meta_select_display (opt_display_name);
|
||||
|
||||
meta_clutter_init ();
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
/* Bring up Wayland. This also launches Xwayland and sets DISPLAY as well... */
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_wayland_init ();
|
||||
#endif
|
||||
|
||||
meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
|
||||
|
||||
if (opt_replace_wm)
|
||||
@ -375,24 +375,7 @@ meta_init (void)
|
||||
|
||||
meta_ui_init ();
|
||||
|
||||
/* If we are running with wayland then we don't wait until we have
|
||||
* an X connection before initializing clutter we instead initialize
|
||||
* it earlier since we need to initialize the GL driver so the driver
|
||||
* can register any needed wayland extensions. */
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
/*
|
||||
* Clutter can only be initialized after the UI.
|
||||
*/
|
||||
meta_clutter_init ();
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
|
||||
* for now.
|
||||
*/
|
||||
clutter_settings = clutter_settings_get_default ();
|
||||
g_object_set (clutter_settings, "window-scaling-factor", 1, NULL);
|
||||
meta_restart_init ();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -444,24 +427,10 @@ meta_register_with_session (void)
|
||||
int
|
||||
meta_run (void)
|
||||
{
|
||||
const gchar *log_domains[] = {
|
||||
NULL, G_LOG_DOMAIN, "Gtk", "Gdk", "GLib",
|
||||
"Pango", "GLib-GObject", "GThread"
|
||||
};
|
||||
guint i;
|
||||
|
||||
/* Load prefs */
|
||||
meta_prefs_init ();
|
||||
meta_prefs_add_listener (prefs_changed_callback, NULL);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(log_domains); i++)
|
||||
g_log_set_handler (log_domains[i],
|
||||
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
|
||||
log_handler, NULL);
|
||||
|
||||
if (g_getenv ("MUTTER_G_FATAL_WARNINGS") != NULL)
|
||||
g_log_set_always_fatal (G_LOG_LEVEL_MASK);
|
||||
|
||||
meta_ui_set_current_theme (meta_prefs_get_theme ());
|
||||
|
||||
/* Try to find some theme that'll work if the theme preference
|
||||
|
@ -309,9 +309,16 @@ accelerator_parse (const gchar *accelerator,
|
||||
keyval = xkb_keysym_from_name (accelerator, XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
if (keyval == XKB_KEY_NoSymbol)
|
||||
{
|
||||
error = TRUE;
|
||||
goto out;
|
||||
}
|
||||
char *with_xf86 = g_strconcat ("XF86", accelerator, NULL);
|
||||
keyval = xkb_keysym_from_name (with_xf86, XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
g_free (with_xf86);
|
||||
|
||||
if (keyval == XKB_KEY_NoSymbol)
|
||||
{
|
||||
error = TRUE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accelerator += len;
|
||||
|
75
src/core/meta-gesture-tracker-private.h
Normal file
75
src/core/meta-gesture-tracker-private.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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>
|
||||
*/
|
||||
|
||||
#ifndef META_GESTURE_TRACKER_PRIVATE_H
|
||||
#define META_GESTURE_TRACKER_PRIVATE_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <meta/window.h>
|
||||
|
||||
#define META_TYPE_GESTURE_TRACKER (meta_gesture_tracker_get_type ())
|
||||
#define META_GESTURE_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_GESTURE_TRACKER, MetaGestureTracker))
|
||||
#define META_GESTURE_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_GESTURE_TRACKER, MetaGestureTrackerClass))
|
||||
#define META_IS_GESTURE_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_GESTURE_TRACKER))
|
||||
#define META_IS_GESTURE_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_GESTURE_TRACKER))
|
||||
#define META_GESTURE_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_GESTURE_TRACKER, MetaGestureTrackerClass))
|
||||
|
||||
typedef struct _MetaGestureTracker MetaGestureTracker;
|
||||
typedef struct _MetaGestureTrackerClass MetaGestureTrackerClass;
|
||||
|
||||
typedef enum {
|
||||
META_SEQUENCE_NONE,
|
||||
META_SEQUENCE_ACCEPTED,
|
||||
META_SEQUENCE_REJECTED,
|
||||
META_SEQUENCE_PENDING_END
|
||||
} MetaSequenceState;
|
||||
|
||||
struct _MetaGestureTracker
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
struct _MetaGestureTrackerClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* state_changed) (MetaGestureTracker *tracker,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state);
|
||||
};
|
||||
|
||||
GType meta_gesture_tracker_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MetaGestureTracker * meta_gesture_tracker_new (void);
|
||||
|
||||
gboolean meta_gesture_tracker_handle_event (MetaGestureTracker *tracker,
|
||||
const ClutterEvent *event);
|
||||
gboolean meta_gesture_tracker_set_sequence_state (MetaGestureTracker *tracker,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state);
|
||||
MetaSequenceState meta_gesture_tracker_get_sequence_state (MetaGestureTracker *tracker,
|
||||
ClutterEventSequence *sequence);
|
||||
gint meta_gesture_tracker_get_n_current_touches (MetaGestureTracker *tracker);
|
||||
|
||||
#endif /* META_GESTURE_TRACKER_PRIVATE_H */
|
582
src/core/meta-gesture-tracker.c
Normal file
582
src/core/meta-gesture-tracker.c
Normal file
@ -0,0 +1,582 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gesture-tracker
|
||||
* @Title: MetaGestureTracker
|
||||
* @Short_Description: Manages gestures on windows/desktop
|
||||
*
|
||||
* Forwards touch events to clutter actors, and accepts/rejects touch sequences
|
||||
* based on the outcome of those.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "meta-gesture-tracker-private.h"
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
#define DISTANCE_THRESHOLD 30
|
||||
|
||||
typedef struct _MetaGestureTrackerPrivate MetaGestureTrackerPrivate;
|
||||
typedef struct _GestureActionData GestureActionData;
|
||||
typedef struct _MetaSequenceInfo MetaSequenceInfo;
|
||||
|
||||
struct _MetaSequenceInfo
|
||||
{
|
||||
MetaGestureTracker *tracker;
|
||||
ClutterEventSequence *sequence;
|
||||
MetaSequenceState state;
|
||||
guint autodeny_timeout_id;
|
||||
gfloat start_x;
|
||||
gfloat start_y;
|
||||
};
|
||||
|
||||
struct _GestureActionData
|
||||
{
|
||||
ClutterGestureAction *gesture;
|
||||
MetaSequenceState state;
|
||||
guint gesture_begin_id;
|
||||
guint gesture_end_id;
|
||||
guint gesture_cancel_id;
|
||||
};
|
||||
|
||||
struct _MetaGestureTrackerPrivate
|
||||
{
|
||||
GHashTable *sequences; /* Hashtable of ClutterEventSequence->MetaSequenceInfo */
|
||||
|
||||
MetaSequenceState stage_state;
|
||||
GArray *stage_gestures; /* Array of GestureActionData */
|
||||
GList *listeners; /* List of ClutterGestureAction */
|
||||
guint autodeny_timeout;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_AUTODENY_TIMEOUT,
|
||||
LAST_PROP,
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[LAST_PROP];
|
||||
|
||||
enum {
|
||||
STATE_CHANGED,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS] = { 0 };
|
||||
|
||||
#define DEFAULT_AUTODENY_TIMEOUT 150
|
||||
|
||||
static void meta_gesture_tracker_untrack_stage (MetaGestureTracker *tracker);
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaGestureTracker, meta_gesture_tracker, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_finalize (GObject *object)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (META_GESTURE_TRACKER (object));
|
||||
|
||||
g_hash_table_destroy (priv->sequences);
|
||||
g_array_free (priv->stage_gestures, TRUE);
|
||||
g_list_free (priv->listeners);
|
||||
|
||||
G_OBJECT_CLASS (meta_gesture_tracker_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (META_GESTURE_TRACKER (object));
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_AUTODENY_TIMEOUT:
|
||||
priv->autodeny_timeout = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (META_GESTURE_TRACKER (object));
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_AUTODENY_TIMEOUT:
|
||||
g_value_set_uint (value, priv->autodeny_timeout);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_class_init (MetaGestureTrackerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_gesture_tracker_finalize;
|
||||
object_class->set_property = meta_gesture_tracker_set_property;
|
||||
object_class->get_property = meta_gesture_tracker_get_property;
|
||||
|
||||
obj_props[PROP_AUTODENY_TIMEOUT] = g_param_spec_uint ("autodeny-timeout",
|
||||
"Auto-deny timeout",
|
||||
"Auto-deny timeout",
|
||||
0, G_MAXUINT, DEFAULT_AUTODENY_TIMEOUT,
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, obj_props);
|
||||
|
||||
signals[STATE_CHANGED] =
|
||||
g_signal_new ("state-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (MetaGestureTrackerClass, state_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
autodeny_sequence (gpointer user_data)
|
||||
{
|
||||
MetaSequenceInfo *info = user_data;
|
||||
|
||||
/* Deny the sequence automatically after the given timeout */
|
||||
if (info->state == META_SEQUENCE_NONE)
|
||||
meta_gesture_tracker_set_sequence_state (info->tracker, info->sequence,
|
||||
META_SEQUENCE_REJECTED);
|
||||
|
||||
info->autodeny_timeout_id = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static MetaSequenceInfo *
|
||||
meta_sequence_info_new (MetaGestureTracker *tracker,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
MetaSequenceInfo *info;
|
||||
guint ms;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
ms = priv->autodeny_timeout;
|
||||
|
||||
info = g_slice_new0 (MetaSequenceInfo);
|
||||
info->tracker = tracker;
|
||||
info->sequence = event->touch.sequence;
|
||||
info->state = META_SEQUENCE_NONE;
|
||||
info->autodeny_timeout_id = g_timeout_add (ms, autodeny_sequence, info);
|
||||
|
||||
clutter_event_get_coords (event, &info->start_x, &info->start_y);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_sequence_info_free (MetaSequenceInfo *info)
|
||||
{
|
||||
if (info->autodeny_timeout_id)
|
||||
g_source_remove (info->autodeny_timeout_id);
|
||||
|
||||
if (info->state == META_SEQUENCE_NONE)
|
||||
meta_gesture_tracker_set_sequence_state (info->tracker, info->sequence,
|
||||
META_SEQUENCE_REJECTED);
|
||||
g_slice_free (MetaSequenceInfo, info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
state_is_applicable (MetaSequenceState prev_state,
|
||||
MetaSequenceState state)
|
||||
{
|
||||
if (prev_state == META_SEQUENCE_PENDING_END)
|
||||
return FALSE;
|
||||
|
||||
/* Don't allow reverting to none */
|
||||
if (state == META_SEQUENCE_NONE)
|
||||
return FALSE;
|
||||
|
||||
/* PENDING_END state is final */
|
||||
if (prev_state == META_SEQUENCE_PENDING_END)
|
||||
return FALSE;
|
||||
|
||||
/* Sequences must be accepted/denied before PENDING_END */
|
||||
if (prev_state == META_SEQUENCE_NONE &&
|
||||
state == META_SEQUENCE_PENDING_END)
|
||||
return FALSE;
|
||||
|
||||
/* Make sequences stick to their accepted/denied state */
|
||||
if (state != META_SEQUENCE_PENDING_END &&
|
||||
prev_state != META_SEQUENCE_NONE)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_gesture_tracker_set_state (MetaGestureTracker *tracker,
|
||||
MetaSequenceState state)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
ClutterEventSequence *sequence;
|
||||
GHashTableIter iter;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
|
||||
if (priv->stage_state != state &&
|
||||
!state_is_applicable (priv->stage_state, state))
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->sequences);
|
||||
priv->stage_state = state;
|
||||
|
||||
while (g_hash_table_iter_next (&iter, (gpointer*) &sequence, NULL))
|
||||
meta_gesture_tracker_set_sequence_state (tracker, sequence, state);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gesture_begin_cb (ClutterGestureAction *gesture,
|
||||
ClutterActor *actor,
|
||||
MetaGestureTracker *tracker)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
|
||||
if (!g_list_find (priv->listeners, gesture) &&
|
||||
meta_gesture_tracker_set_state (tracker, META_SEQUENCE_ACCEPTED))
|
||||
priv->listeners = g_list_prepend (priv->listeners, gesture);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gesture_end_cb (ClutterGestureAction *gesture,
|
||||
ClutterActor *actor,
|
||||
MetaGestureTracker *tracker)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
priv->listeners = g_list_remove (priv->listeners, gesture);
|
||||
|
||||
if (!priv->listeners)
|
||||
meta_gesture_tracker_untrack_stage (tracker);
|
||||
}
|
||||
|
||||
static void
|
||||
gesture_cancel_cb (ClutterGestureAction *gesture,
|
||||
ClutterActor *actor,
|
||||
MetaGestureTracker *tracker)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
|
||||
if (g_list_find (priv->listeners, gesture))
|
||||
{
|
||||
priv->listeners = g_list_remove (priv->listeners, gesture);
|
||||
|
||||
if (!priv->listeners)
|
||||
meta_gesture_tracker_set_state (tracker, META_SEQUENCE_PENDING_END);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cancel_and_unref_gesture_cb (ClutterGestureAction *action)
|
||||
{
|
||||
clutter_gesture_action_cancel (action);
|
||||
g_object_unref (action);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_gesture_data (GestureActionData *data)
|
||||
{
|
||||
g_signal_handler_disconnect (data->gesture, data->gesture_begin_id);
|
||||
g_signal_handler_disconnect (data->gesture, data->gesture_end_id);
|
||||
g_signal_handler_disconnect (data->gesture, data->gesture_cancel_id);
|
||||
|
||||
/* Defer cancellation to an idle, as it may happen within event handling */
|
||||
g_idle_add ((GSourceFunc) cancel_and_unref_gesture_cb, data->gesture);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_init (MetaGestureTracker *tracker)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
priv->sequences = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) meta_sequence_info_free);
|
||||
priv->stage_gestures = g_array_new (FALSE, FALSE, sizeof (GestureActionData));
|
||||
g_array_set_clear_func (priv->stage_gestures, (GDestroyNotify) clear_gesture_data);
|
||||
}
|
||||
|
||||
MetaGestureTracker *
|
||||
meta_gesture_tracker_new (void)
|
||||
{
|
||||
return g_object_new (META_TYPE_GESTURE_TRACKER, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_track_stage (MetaGestureTracker *tracker,
|
||||
ClutterActor *stage)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
GList *actions, *l;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
actions = clutter_actor_get_actions (stage);
|
||||
|
||||
for (l = actions; l; l = l->next)
|
||||
{
|
||||
GestureActionData data;
|
||||
|
||||
if (!CLUTTER_IS_GESTURE_ACTION (l->data))
|
||||
continue;
|
||||
|
||||
data.gesture = g_object_ref (l->data);
|
||||
data.state = META_SEQUENCE_NONE;
|
||||
data.gesture_begin_id =
|
||||
g_signal_connect (data.gesture, "gesture-begin",
|
||||
G_CALLBACK (gesture_begin_cb), tracker);
|
||||
data.gesture_end_id =
|
||||
g_signal_connect (data.gesture, "gesture-end",
|
||||
G_CALLBACK (gesture_end_cb), tracker);
|
||||
data.gesture_cancel_id =
|
||||
g_signal_connect (data.gesture, "gesture-cancel",
|
||||
G_CALLBACK (gesture_cancel_cb), tracker);
|
||||
g_array_append_val (priv->stage_gestures, data);
|
||||
}
|
||||
|
||||
g_list_free (actions);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gesture_tracker_untrack_stage (MetaGestureTracker *tracker)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
priv->stage_state = META_SEQUENCE_NONE;
|
||||
|
||||
g_hash_table_remove_all (priv->sequences);
|
||||
|
||||
if (priv->stage_gestures->len > 0)
|
||||
g_array_remove_range (priv->stage_gestures, 0, priv->stage_gestures->len);
|
||||
|
||||
g_list_free (priv->listeners);
|
||||
priv->listeners = NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gesture_tracker_handle_event (MetaGestureTracker *tracker,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
ClutterEventSequence *sequence;
|
||||
MetaSequenceState state;
|
||||
MetaSequenceInfo *info;
|
||||
ClutterActor *stage;
|
||||
gfloat x, y;
|
||||
|
||||
sequence = clutter_event_get_event_sequence (event);
|
||||
|
||||
if (!sequence)
|
||||
return FALSE;
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
stage = CLUTTER_ACTOR (clutter_event_get_stage (event));
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_TOUCH_BEGIN:
|
||||
if (g_hash_table_size (priv->sequences) == 0)
|
||||
meta_gesture_tracker_track_stage (tracker, stage);
|
||||
|
||||
info = meta_sequence_info_new (tracker, event);
|
||||
g_hash_table_insert (priv->sequences, sequence, info);
|
||||
|
||||
if (priv->stage_gestures->len == 0)
|
||||
{
|
||||
/* If no gestures are attached, reject the sequence right away */
|
||||
meta_gesture_tracker_set_sequence_state (tracker, sequence,
|
||||
META_SEQUENCE_REJECTED);
|
||||
}
|
||||
else if (priv->stage_state != META_SEQUENCE_NONE)
|
||||
{
|
||||
/* Make the sequence state match the general state */
|
||||
meta_gesture_tracker_set_sequence_state (tracker, sequence,
|
||||
priv->stage_state);
|
||||
}
|
||||
state = info->state;
|
||||
break;
|
||||
case CLUTTER_TOUCH_END:
|
||||
info = g_hash_table_lookup (priv->sequences, sequence);
|
||||
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
/* If nothing was done yet about the sequence, reject it so X11
|
||||
* clients may see it
|
||||
*/
|
||||
if (info->state == META_SEQUENCE_NONE)
|
||||
meta_gesture_tracker_set_sequence_state (tracker, sequence,
|
||||
META_SEQUENCE_REJECTED);
|
||||
|
||||
state = info->state;
|
||||
g_hash_table_remove (priv->sequences, sequence);
|
||||
|
||||
if (g_hash_table_size (priv->sequences) == 0)
|
||||
meta_gesture_tracker_untrack_stage (tracker);
|
||||
break;
|
||||
case CLUTTER_TOUCH_UPDATE:
|
||||
info = g_hash_table_lookup (priv->sequences, sequence);
|
||||
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
|
||||
if (info->state == META_SEQUENCE_NONE &&
|
||||
(ABS (info->start_x - x) > DISTANCE_THRESHOLD ||
|
||||
ABS (info->start_y - y) > DISTANCE_THRESHOLD))
|
||||
meta_gesture_tracker_set_sequence_state (tracker, sequence,
|
||||
META_SEQUENCE_REJECTED);
|
||||
state = info->state;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* As soon as a sequence is accepted, we replay it to
|
||||
* the stage as a captured event, and make sure it's never
|
||||
* propagated anywhere else. Since ClutterGestureAction does
|
||||
* all its event handling from a captured-event handler on
|
||||
* the stage, this effectively acts as a "sequence grab" on
|
||||
* gesture actions.
|
||||
*
|
||||
* Sequences that aren't (yet or never) in an accepted state
|
||||
* will go through, these events will get processed through
|
||||
* the compositor, and eventually through clutter, still
|
||||
* triggering the gestures capturing events on the stage, and
|
||||
* possibly resulting in MetaSequenceState changes.
|
||||
*/
|
||||
if (state == META_SEQUENCE_ACCEPTED)
|
||||
{
|
||||
clutter_actor_event (CLUTTER_ACTOR (clutter_event_get_stage (event)),
|
||||
event, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gesture_tracker_set_sequence_state (MetaGestureTracker *tracker,
|
||||
ClutterEventSequence *sequence,
|
||||
MetaSequenceState state)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
MetaSequenceInfo *info;
|
||||
|
||||
g_return_val_if_fail (META_IS_GESTURE_TRACKER (tracker), FALSE);
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
info = g_hash_table_lookup (priv->sequences, sequence);
|
||||
|
||||
if (!info)
|
||||
return FALSE;
|
||||
else if (state == info->state)
|
||||
return TRUE;
|
||||
|
||||
if (!state_is_applicable (info->state, state))
|
||||
return FALSE;
|
||||
|
||||
/* Unset autodeny timeout */
|
||||
if (info->autodeny_timeout_id)
|
||||
{
|
||||
g_source_remove (info->autodeny_timeout_id);
|
||||
info->autodeny_timeout_id = 0;
|
||||
}
|
||||
|
||||
info->state = state;
|
||||
g_signal_emit (tracker, signals[STATE_CHANGED], 0, sequence, info->state);
|
||||
|
||||
/* If the sequence was denied, set immediately to PENDING_END after emission */
|
||||
if (state == META_SEQUENCE_REJECTED)
|
||||
{
|
||||
info->state = META_SEQUENCE_PENDING_END;
|
||||
g_signal_emit (tracker, signals[STATE_CHANGED], 0, sequence, info->state);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaSequenceState
|
||||
meta_gesture_tracker_get_sequence_state (MetaGestureTracker *tracker,
|
||||
ClutterEventSequence *sequence)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
MetaSequenceInfo *info;
|
||||
|
||||
g_return_val_if_fail (META_IS_GESTURE_TRACKER (tracker), META_SEQUENCE_PENDING_END);
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
info = g_hash_table_lookup (priv->sequences, sequence);
|
||||
|
||||
if (!info)
|
||||
return META_SEQUENCE_PENDING_END;
|
||||
|
||||
return info->state;
|
||||
}
|
||||
|
||||
gint
|
||||
meta_gesture_tracker_get_n_current_touches (MetaGestureTracker *tracker)
|
||||
{
|
||||
MetaGestureTrackerPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (META_IS_GESTURE_TRACKER (tracker), 0);
|
||||
|
||||
priv = meta_gesture_tracker_get_instance_private (tracker);
|
||||
return g_hash_table_size (priv->sequences);
|
||||
}
|
220
src/core/prefs.c
220
src/core/prefs.c
@ -28,7 +28,6 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <meta/prefs.h>
|
||||
#include "ui.h"
|
||||
#include "util-private.h"
|
||||
#include "meta-plugin-manager.h"
|
||||
#include <glib.h>
|
||||
@ -53,9 +52,7 @@
|
||||
#define KEY_GNOME_ACCESSIBILITY "toolkit-accessibility"
|
||||
#define KEY_GNOME_ANIMATIONS "enable-animations"
|
||||
#define KEY_GNOME_CURSOR_THEME "cursor-theme"
|
||||
#define KEY_GNOME_CURSOR_SIZE "cursor-size"
|
||||
#define KEY_XKB_OPTIONS "xkb-options"
|
||||
#define KEY_XSETTINGS_OVERRIDES "overrides"
|
||||
|
||||
#define KEY_OVERLAY_KEY "overlay-key"
|
||||
#define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
|
||||
@ -67,6 +64,7 @@
|
||||
#define SCHEMA_INTERFACE "org.gnome.desktop.interface"
|
||||
#define SCHEMA_INPUT_SOURCES "org.gnome.desktop.input-sources"
|
||||
#define SCHEMA_XSETTINGS "org.gnome.settings-daemon.plugins.xsettings"
|
||||
#define SCHEMA_MOUSE "org.gnome.settings-daemon.peripherals.mouse"
|
||||
|
||||
#define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
|
||||
|
||||
@ -101,6 +99,7 @@ static gboolean gnome_animations = TRUE;
|
||||
static char *cursor_theme = NULL;
|
||||
static int cursor_size = 24;
|
||||
static int draggable_border_width = 10;
|
||||
static int drag_threshold;
|
||||
static gboolean resize_with_right_button = FALSE;
|
||||
static gboolean edge_tiling = FALSE;
|
||||
static gboolean force_fullscreen = TRUE;
|
||||
@ -132,9 +131,13 @@ static void bindings_changed (GSettings *settings,
|
||||
gchar *key,
|
||||
gpointer data);
|
||||
|
||||
static void xsettings_overrides_changed (GSettings *settings,
|
||||
gchar *key,
|
||||
gpointer data);
|
||||
static void shell_shows_app_menu_changed (GtkSettings *settings,
|
||||
GParamSpec *pspec,
|
||||
gpointer data);
|
||||
|
||||
static void update_cursor_size (GtkSettings *settings,
|
||||
GParamSpec *pspec,
|
||||
gpointer data);
|
||||
|
||||
static void queue_changed (MetaPreference pref);
|
||||
|
||||
@ -478,13 +481,6 @@ static MetaIntPreference preferences_int[] =
|
||||
},
|
||||
&auto_raise_delay
|
||||
},
|
||||
{
|
||||
{ "cursor-size",
|
||||
SCHEMA_INTERFACE,
|
||||
META_PREF_CURSOR_SIZE,
|
||||
},
|
||||
&cursor_size
|
||||
},
|
||||
{
|
||||
{ "draggable-border-width",
|
||||
SCHEMA_MUTTER,
|
||||
@ -492,6 +488,13 @@ static MetaIntPreference preferences_int[] =
|
||||
},
|
||||
&draggable_border_width
|
||||
},
|
||||
{
|
||||
{ "drag-threshold",
|
||||
SCHEMA_MOUSE,
|
||||
META_PREF_DRAG_THRESHOLD,
|
||||
},
|
||||
&drag_threshold
|
||||
},
|
||||
{ { NULL, 0, 0 }, NULL },
|
||||
};
|
||||
|
||||
@ -943,24 +946,6 @@ queue_changed (MetaPreference pref)
|
||||
/* Initialisation. */
|
||||
/****************************************************************************/
|
||||
|
||||
static GSettings *
|
||||
get_xsettings_settings (void)
|
||||
{
|
||||
GSettings *settings = NULL;
|
||||
GSettingsSchema *schema;
|
||||
|
||||
schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
|
||||
SCHEMA_XSETTINGS, FALSE);
|
||||
|
||||
if (schema)
|
||||
{
|
||||
settings = g_settings_new_full (schema, NULL, NULL);
|
||||
g_settings_schema_unref (schema);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
void
|
||||
meta_prefs_init (void)
|
||||
{
|
||||
@ -978,6 +963,10 @@ meta_prefs_init (void)
|
||||
g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
|
||||
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_MUTTER), settings);
|
||||
|
||||
settings = g_settings_new (SCHEMA_MOUSE);
|
||||
g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
|
||||
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_MOUSE), settings);
|
||||
|
||||
/* Individual keys we watch outside of our schemas */
|
||||
settings = g_settings_new (SCHEMA_INTERFACE);
|
||||
g_signal_connect (settings, "changed::" KEY_GNOME_ACCESSIBILITY,
|
||||
@ -986,19 +975,14 @@ meta_prefs_init (void)
|
||||
G_CALLBACK (settings_changed), NULL);
|
||||
g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_THEME,
|
||||
G_CALLBACK (settings_changed), NULL);
|
||||
g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_SIZE,
|
||||
G_CALLBACK (settings_changed), NULL);
|
||||
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
|
||||
|
||||
settings = get_xsettings_settings ();
|
||||
if (settings)
|
||||
{
|
||||
g_signal_connect (settings, "changed::" KEY_XSETTINGS_OVERRIDES,
|
||||
G_CALLBACK (xsettings_overrides_changed), NULL);
|
||||
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_XSETTINGS), settings);
|
||||
g_signal_connect (gtk_settings_get_default (),
|
||||
"notify::gtk-shell-shows-app-menu",
|
||||
G_CALLBACK (shell_shows_app_menu_changed), NULL);
|
||||
|
||||
xsettings_overrides_changed (settings, KEY_XSETTINGS_OVERRIDES, NULL);
|
||||
}
|
||||
g_signal_connect (gtk_settings_get_default (), "notify::gtk-cursor-theme-size",
|
||||
G_CALLBACK (update_cursor_size), NULL);
|
||||
|
||||
settings = g_settings_new (SCHEMA_INPUT_SOURCES);
|
||||
g_signal_connect (settings, "changed::" KEY_XKB_OPTIONS,
|
||||
@ -1020,6 +1004,9 @@ meta_prefs_init (void)
|
||||
handle_preference_init_string_array ();
|
||||
handle_preference_init_int ();
|
||||
|
||||
update_cursor_size (gtk_settings_get_default (), NULL, NULL);
|
||||
shell_shows_app_menu_changed (gtk_settings_get_default (), NULL, NULL);
|
||||
|
||||
init_bindings ();
|
||||
}
|
||||
|
||||
@ -1198,8 +1185,9 @@ settings_changed (GSettings *settings,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Someone added a preference of an unhandled type */
|
||||
g_assert_not_reached ();
|
||||
/* Unknown preference type. This quite likely simply isn't
|
||||
* a preference we track changes to. */
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_unref (value);
|
||||
@ -1219,44 +1207,49 @@ bindings_changed (GSettings *settings,
|
||||
g_strfreev (strokes);
|
||||
}
|
||||
|
||||
/* The fallback app menu should be enabled if either we are not
|
||||
* showing the app menu (e.g. when using the default plugin) or
|
||||
* with a corresponding XSettings override; we ignore the former
|
||||
* and assume that we always show the app menu, not least
|
||||
* because we rely on the compositor implementation to display
|
||||
* the fallback ...
|
||||
*/
|
||||
static void
|
||||
xsettings_overrides_changed (GSettings *settings,
|
||||
gchar *key,
|
||||
gpointer data)
|
||||
shell_shows_app_menu_changed (GtkSettings *settings,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
GVariant *value;
|
||||
GVariantDict overrides;
|
||||
int shell_shows_app_menu = 1;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
if (!g_settings_get_boolean (settings, "active"))
|
||||
goto out;
|
||||
g_object_get (settings,
|
||||
"gtk-shell-shows-app-menu", &shell_shows_app_menu,
|
||||
NULL);
|
||||
|
||||
value = g_settings_get_value (settings, KEY_XSETTINGS_OVERRIDES);
|
||||
|
||||
g_variant_dict_init (&overrides, value);
|
||||
g_variant_unref (value);
|
||||
|
||||
g_variant_dict_lookup (&overrides,
|
||||
"Gtk/ShellShowsAppMenu", "i", &shell_shows_app_menu);
|
||||
g_variant_dict_clear (&overrides);
|
||||
|
||||
changed = (show_fallback_app_menu == !!shell_shows_app_menu);
|
||||
|
||||
out:
|
||||
show_fallback_app_menu = !shell_shows_app_menu;
|
||||
|
||||
if (changed)
|
||||
queue_changed (META_PREF_BUTTON_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
update_cursor_size (GtkSettings *settings,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
GdkScreen *screen = gdk_screen_get_default ();
|
||||
GValue value = G_VALUE_INIT;
|
||||
int xsettings_cursor_size = 24;
|
||||
|
||||
g_value_init (&value, G_TYPE_INT);
|
||||
if (gdk_screen_get_setting (screen, "gtk-cursor-theme-size", &value))
|
||||
{
|
||||
xsettings_cursor_size = g_value_get_int (&value);
|
||||
}
|
||||
|
||||
if (xsettings_cursor_size != cursor_size)
|
||||
{
|
||||
cursor_size = xsettings_cursor_size;
|
||||
queue_changed (META_PREF_CURSOR_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* maybe_give_disable_workaround_warning:
|
||||
*
|
||||
@ -1668,43 +1661,43 @@ button_layout_handler (GVariant *value,
|
||||
g_strfreev (sides);
|
||||
|
||||
/* Invert the button layout for RTL languages */
|
||||
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
|
||||
{
|
||||
MetaButtonLayout rtl_layout;
|
||||
int j;
|
||||
if (meta_get_locale_direction() == META_LOCALE_DIRECTION_RTL)
|
||||
{
|
||||
MetaButtonLayout rtl_layout;
|
||||
int j;
|
||||
|
||||
for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
|
||||
if (j == 0)
|
||||
rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
|
||||
else
|
||||
rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
|
||||
}
|
||||
for (; j < MAX_BUTTONS_PER_CORNER; j++)
|
||||
{
|
||||
rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
|
||||
rtl_layout.right_buttons_has_spacer[j] = FALSE;
|
||||
}
|
||||
for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
|
||||
if (j == 0)
|
||||
rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
|
||||
else
|
||||
rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
|
||||
}
|
||||
for (; j < MAX_BUTTONS_PER_CORNER; j++)
|
||||
{
|
||||
rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
|
||||
rtl_layout.right_buttons_has_spacer[j] = FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
|
||||
if (j == 0)
|
||||
rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
|
||||
else
|
||||
rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
|
||||
}
|
||||
for (; j < MAX_BUTTONS_PER_CORNER; j++)
|
||||
{
|
||||
rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
|
||||
rtl_layout.left_buttons_has_spacer[j] = FALSE;
|
||||
}
|
||||
for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
|
||||
if (j == 0)
|
||||
rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
|
||||
else
|
||||
rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
|
||||
}
|
||||
for (; j < MAX_BUTTONS_PER_CORNER; j++)
|
||||
{
|
||||
rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
|
||||
rtl_layout.left_buttons_has_spacer[j] = FALSE;
|
||||
}
|
||||
|
||||
new_layout = rtl_layout;
|
||||
}
|
||||
new_layout = rtl_layout;
|
||||
}
|
||||
|
||||
if (!button_layout_equal (&button_layout, &new_layout))
|
||||
{
|
||||
@ -1908,6 +1901,9 @@ meta_preference_to_string (MetaPreference pref)
|
||||
case META_PREF_DRAGGABLE_BORDER_WIDTH:
|
||||
return "DRAGGABLE_BORDER_WIDTH";
|
||||
|
||||
case META_PREF_DRAG_THRESHOLD:
|
||||
return "DRAG_TRHESHOLD";
|
||||
|
||||
case META_PREF_DYNAMIC_WORKSPACES:
|
||||
return "DYNAMIC_WORKSPACES";
|
||||
|
||||
@ -2001,23 +1997,6 @@ update_binding (MetaKeyPref *binding,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bug 329676: Bindings which can be shifted must not have no modifiers,
|
||||
* nor only SHIFT as a modifier.
|
||||
*/
|
||||
|
||||
if (binding->add_shift &&
|
||||
0 != keysym &&
|
||||
(META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
|
||||
{
|
||||
meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
|
||||
"such as Ctrl or Alt.\n",
|
||||
binding->name, strokes[i]);
|
||||
|
||||
/* Value is kept and will thus be removed next time we save the key.
|
||||
* Changing the key in response to a modification could lead to cyclic calls. */
|
||||
continue;
|
||||
}
|
||||
|
||||
combo = g_malloc0 (sizeof (MetaKeyCombo));
|
||||
combo->keysym = keysym;
|
||||
combo->keycode = keycode;
|
||||
@ -2193,7 +2172,6 @@ meta_prefs_add_keybinding (const char *name,
|
||||
pref->settings = g_object_ref (settings);
|
||||
pref->action = action;
|
||||
pref->combos = NULL;
|
||||
pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
|
||||
pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0;
|
||||
pref->builtin = (flags & META_KEY_BINDING_BUILTIN) != 0;
|
||||
|
||||
@ -2373,6 +2351,12 @@ meta_prefs_get_draggable_border_width (void)
|
||||
return draggable_border_width;
|
||||
}
|
||||
|
||||
int
|
||||
meta_prefs_get_drag_threshold (void)
|
||||
{
|
||||
return drag_threshold;
|
||||
}
|
||||
|
||||
void
|
||||
meta_prefs_set_force_fullscreen (gboolean whether)
|
||||
{
|
||||
|
82
src/core/restart-helper.c
Normal file
82
src/core/restart-helper.c
Normal file
@ -0,0 +1,82 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* SECTION:restart-helper
|
||||
* @short_description: helper program during a restart
|
||||
*
|
||||
* To smoothly restart Mutter, we want to keep the composite
|
||||
* overlay window enabled during the restart. This is done by
|
||||
* spawning this program, which keeps a reference to the the composite
|
||||
* overlay window until Mutter picks it back up.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
Display *display = XOpenDisplay (NULL);
|
||||
Window selection_window;
|
||||
XSetWindowAttributes xwa;
|
||||
unsigned long mask = 0;
|
||||
|
||||
xwa.override_redirect = True;
|
||||
mask |= CWOverrideRedirect;
|
||||
|
||||
|
||||
XCompositeGetOverlayWindow (display, DefaultRootWindow (display));
|
||||
|
||||
selection_window = XCreateWindow (display,
|
||||
DefaultRootWindow (display),
|
||||
-100, -100, 1, 1, 0,
|
||||
0,
|
||||
InputOnly,
|
||||
DefaultVisual (display, DefaultScreen (display)),
|
||||
mask, &xwa);
|
||||
|
||||
XSetSelectionOwner (display,
|
||||
XInternAtom (display, "_MUTTER_RESTART_HELPER", False),
|
||||
selection_window,
|
||||
CurrentTime);
|
||||
|
||||
/* Mutter looks for an (arbitrary) line printed to stdout to know that
|
||||
* we have started and have a reference to the COW. XSync() so that
|
||||
* everything is set on the X server before Mutter starts restarting.
|
||||
*/
|
||||
XSync (display, False);
|
||||
|
||||
printf ("STARTED\n");
|
||||
fflush (stdout);
|
||||
|
||||
while (True)
|
||||
{
|
||||
XEvent xev;
|
||||
|
||||
XNextEvent (display, &xev);
|
||||
/* Mutter restarted and unset the selection to indicate that
|
||||
* it has a reference on the COW again */
|
||||
if (xev.xany.type == SelectionClear)
|
||||
return 0;
|
||||
}
|
||||
}
|
212
src/core/restart.c
Normal file
212
src/core/restart.c
Normal file
@ -0,0 +1,212 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SECTION:restart
|
||||
* @short_description: Smoothly restart the compositor
|
||||
*
|
||||
* There are some cases where we need to restart Mutter in order
|
||||
* to deal with changes in state - the particular case inspiring
|
||||
* this is enabling or disabling stereo output. To make this
|
||||
* fairly smooth for the user, we need to do two things:
|
||||
*
|
||||
* - Display a message to the user and make sure that it is
|
||||
* actually painted before we exit.
|
||||
* - Use a helper program so that the Composite Overlay Window
|
||||
* isn't unmapped and mapped.
|
||||
*
|
||||
* This handles both of these.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
|
||||
#include <meta/main.h>
|
||||
#include "ui.h"
|
||||
#include "util-private.h"
|
||||
#include "display-private.h"
|
||||
|
||||
static gboolean restart_helper_started = FALSE;
|
||||
static gboolean restart_message_shown = FALSE;
|
||||
static gboolean is_restart = FALSE;
|
||||
|
||||
void
|
||||
meta_restart_init (void)
|
||||
{
|
||||
Display *xdisplay = meta_ui_get_display ();
|
||||
Atom atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
|
||||
Window restart_helper_window = None;
|
||||
|
||||
restart_helper_window = XGetSelectionOwner (xdisplay, atom_restart_helper);
|
||||
if (restart_helper_window)
|
||||
is_restart = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
restart_check_ready (void)
|
||||
{
|
||||
if (restart_helper_started && restart_message_shown)
|
||||
meta_display_request_restart (meta_get_display ());
|
||||
}
|
||||
|
||||
static void
|
||||
restart_helper_read_line_callback (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gsize length;
|
||||
char *line = g_data_input_stream_read_line_finish_utf8 (G_DATA_INPUT_STREAM (source_object),
|
||||
res,
|
||||
&length, &error);
|
||||
if (line == NULL)
|
||||
{
|
||||
meta_warning ("Failed to read output from restart helper%s%s\n",
|
||||
error ? ": " : NULL,
|
||||
error ? error->message : NULL);
|
||||
}
|
||||
else
|
||||
g_free (line); /* We don't actually care what the restart helper outputs */
|
||||
|
||||
g_object_unref (source_object);
|
||||
|
||||
restart_helper_started = TRUE;
|
||||
restart_check_ready ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
restart_message_painted (gpointer data)
|
||||
{
|
||||
restart_message_shown = TRUE;
|
||||
restart_check_ready ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_restart:
|
||||
* @message: message to display to the user.
|
||||
*
|
||||
* Starts the process of restarting the compositor. Note that Mutter's
|
||||
* involvement here is to make the restart visually smooth for the
|
||||
* user - it cannot itself safely reexec a program that embeds libmuttter.
|
||||
* So in order for this to work, the compositor must handle two
|
||||
* signals - MetaDisplay::show-restart-message, to display the
|
||||
* message passed here on the Clutter stage, and ::restart to actually
|
||||
* reexec the compositor.
|
||||
*/
|
||||
void
|
||||
meta_restart (const char *message)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display();
|
||||
GInputStream *unix_stream;
|
||||
GDataInputStream *data_stream;
|
||||
GError *error = NULL;
|
||||
int helper_out_fd;
|
||||
|
||||
static const char * const helper_argv[] = {
|
||||
MUTTER_LIBEXECDIR "/mutter-restart-helper", NULL
|
||||
};
|
||||
|
||||
if (meta_display_show_restart_message (display, message))
|
||||
{
|
||||
/* Wait until the stage was painted */
|
||||
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
|
||||
restart_message_painted,
|
||||
NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can't show the message, show the message as soon as the
|
||||
* restart helper starts
|
||||
*/
|
||||
restart_message_painted (NULL);
|
||||
}
|
||||
|
||||
/* We also need to wait for the restart helper to get its
|
||||
* reference to the Composite Overlay Window.
|
||||
*/
|
||||
if (!g_spawn_async_with_pipes (NULL, /* working directory */
|
||||
(char **)helper_argv,
|
||||
NULL, /* envp */
|
||||
G_SPAWN_DEFAULT,
|
||||
NULL, NULL, /* child_setup */
|
||||
NULL, /* child_pid */
|
||||
NULL, /* standard_input */
|
||||
&helper_out_fd,
|
||||
NULL, /* standard_error */
|
||||
&error))
|
||||
{
|
||||
meta_warning ("Failed to start restart helper: %s\n", error->message);
|
||||
goto error;
|
||||
}
|
||||
|
||||
unix_stream = g_unix_input_stream_new (helper_out_fd, TRUE);
|
||||
data_stream = g_data_input_stream_new (unix_stream);
|
||||
g_object_unref (unix_stream);
|
||||
|
||||
g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
|
||||
NULL, restart_helper_read_line_callback,
|
||||
&error);
|
||||
if (error != NULL)
|
||||
{
|
||||
meta_warning ("Failed to read from restart helper: %s\n", error->message);
|
||||
g_object_unref (data_stream);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
/* If starting the restart helper fails, then we just go ahead and restart
|
||||
* immediately. We won't get a smooth transition, since the overlay window
|
||||
* will be destroyed and recreated, but otherwise it will work fine.
|
||||
*/
|
||||
restart_helper_started = TRUE;
|
||||
restart_check_ready ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
meta_restart_finish (void)
|
||||
{
|
||||
if (is_restart)
|
||||
{
|
||||
Display *xdisplay = meta_display_get_xdisplay (meta_get_display ());
|
||||
Atom atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
|
||||
XSetSelectionOwner (xdisplay, atom_restart_helper, None, CurrentTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_is_restart:
|
||||
*
|
||||
* Returns %TRUE if this instance of Mutter comes from Mutter
|
||||
* restarting itself (for example to enable/disable stereo.)
|
||||
* See meta_restart(). If this is the case, any startup visuals
|
||||
* or animations should be suppressed.
|
||||
*/
|
||||
gboolean
|
||||
meta_is_restart (void)
|
||||
{
|
||||
return is_restart;
|
||||
}
|
@ -38,8 +38,8 @@
|
||||
#include "ui.h"
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
|
||||
gpointer user_data);
|
||||
typedef void (* MetaScreenWindowFunc) (MetaWindow *window,
|
||||
gpointer user_data);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -119,6 +119,8 @@ struct _MetaScreen
|
||||
* and restack them below a guard window. When using a compositor
|
||||
* this allows us to provide live previews of unmapped windows */
|
||||
Window guard_window;
|
||||
|
||||
Window composite_overlay_window;
|
||||
};
|
||||
|
||||
struct _MetaScreenClass
|
||||
@ -138,6 +140,7 @@ void meta_screen_free (MetaScreen *scree
|
||||
void meta_screen_init_workspaces (MetaScreen *screen);
|
||||
void meta_screen_manage_all_windows (MetaScreen *screen);
|
||||
void meta_screen_foreach_window (MetaScreen *screen,
|
||||
MetaListWindowsFlags flags,
|
||||
MetaScreenWindowFunc func,
|
||||
gpointer data);
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <locale.h>
|
||||
@ -55,12 +56,13 @@
|
||||
#include "x11/window-x11.h"
|
||||
#include "x11/xprops.h"
|
||||
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
|
||||
static char* get_screen_name (MetaDisplay *display,
|
||||
int number);
|
||||
|
||||
static void update_num_workspaces (MetaScreen *screen,
|
||||
guint32 timestamp);
|
||||
static void update_focus_mode (MetaScreen *screen);
|
||||
static void set_workspace_names (MetaScreen *screen);
|
||||
static void prefs_changed_callback (MetaPreference pref,
|
||||
gpointer data);
|
||||
@ -404,17 +406,13 @@ meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
|
||||
static void
|
||||
reload_monitor_infos (MetaScreen *screen)
|
||||
{
|
||||
GList *tmp;
|
||||
GList *l;
|
||||
MetaMonitorManager *manager;
|
||||
|
||||
tmp = screen->workspaces;
|
||||
while (tmp != NULL)
|
||||
for (l = screen->workspaces; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWorkspace *space = tmp->data;
|
||||
|
||||
MetaWorkspace *space = l->data;
|
||||
meta_workspace_invalidate_work_area (space);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
/* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
|
||||
@ -443,7 +441,6 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
XSetWindowAttributes attributes;
|
||||
Window guard_window;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
attributes.event_mask = NoEventMask;
|
||||
attributes.override_redirect = True;
|
||||
@ -469,29 +466,45 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
XStoreName (xdisplay, guard_window, "mutter guard window");
|
||||
|
||||
{
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
|
||||
Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend);
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XISelectEvents (xdisplay, guard_window, &mask, 1);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
|
||||
/* Sync on the connection we created the window on to
|
||||
* make sure it's created before we select on it on the
|
||||
* backend connection. */
|
||||
XSync (xdisplay, False);
|
||||
|
||||
XISelectEvents (backend_xdisplay, guard_window, &mask, 1);
|
||||
}
|
||||
}
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = guard_window;
|
||||
meta_stack_tracker_record_add (screen->stack_tracker,
|
||||
&stack_window,
|
||||
guard_window,
|
||||
create_serial);
|
||||
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
&stack_window,
|
||||
XNextRequest (xdisplay));
|
||||
XLowerWindow (xdisplay, guard_window);
|
||||
meta_stack_tracker_lower (screen->stack_tracker,
|
||||
guard_window);
|
||||
XMapWindow (xdisplay, guard_window);
|
||||
return guard_window;
|
||||
}
|
||||
|
||||
/* Set a black background on the root window so that we don't
|
||||
* see confusing old copies of old windows when debugging
|
||||
* and testing. */
|
||||
static void
|
||||
meta_screen_set_background (MetaScreen *screen)
|
||||
{
|
||||
XSetWindowBackground (screen->display->xdisplay, screen->xroot, 0x00000000);
|
||||
}
|
||||
|
||||
MetaScreen*
|
||||
meta_screen_new (MetaDisplay *display,
|
||||
int number,
|
||||
@ -611,24 +624,15 @@ meta_screen_new (MetaDisplay *display,
|
||||
/* select our root window events */
|
||||
meta_error_trap_push (display);
|
||||
|
||||
/* We need to or with the existing event mask since
|
||||
* gtk+ may be interested in other events.
|
||||
*/
|
||||
{
|
||||
long event_mask;
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
XWindowAttributes attr;
|
||||
|
||||
meta_core_add_old_event_mask (xdisplay, xroot, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
#ifdef HAVE_XI23
|
||||
if (META_DISPLAY_HAS_XINPUT_23 (display))
|
||||
{
|
||||
@ -640,9 +644,6 @@ meta_screen_new (MetaDisplay *display,
|
||||
|
||||
event_mask = (SubstructureRedirectMask | SubstructureNotifyMask |
|
||||
StructureNotifyMask | ColormapChangeMask | PropertyChangeMask);
|
||||
if (XGetWindowAttributes (xdisplay, xroot, &attr))
|
||||
event_mask |= attr.your_event_mask;
|
||||
|
||||
XSelectInput (xdisplay, xroot, event_mask);
|
||||
}
|
||||
|
||||
@ -656,6 +657,9 @@ meta_screen_new (MetaDisplay *display,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Select for cursor changes so the cursor tracker is up to date. */
|
||||
XFixesSelectCursorInput (xdisplay, xroot, XFixesDisplayCursorNotifyMask);
|
||||
|
||||
screen = g_object_new (META_TYPE_SCREEN, NULL);
|
||||
screen->closing = 0;
|
||||
|
||||
@ -696,9 +700,16 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->starting_corner = META_SCREEN_TOPLEFT;
|
||||
screen->guard_window = None;
|
||||
|
||||
screen->composite_overlay_window = XCompositeGetOverlayWindow (xdisplay, xroot);
|
||||
|
||||
/* Now that we've gotten taken a reference count on the COW, we
|
||||
* can close the helper that is holding on to it */
|
||||
meta_restart_finish ();
|
||||
|
||||
reload_monitor_infos (screen);
|
||||
|
||||
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
|
||||
meta_screen_set_background (screen);
|
||||
|
||||
/* Handle creating a no_focus_window for this screen */
|
||||
screen->no_focus_window =
|
||||
@ -776,7 +787,6 @@ meta_screen_init_workspaces (MetaScreen *screen)
|
||||
else
|
||||
meta_verbose ("No _NET_CURRENT_DESKTOP present\n");
|
||||
|
||||
meta_workspace_activate (screen->workspaces->data, timestamp);
|
||||
update_num_workspaces (screen, timestamp);
|
||||
|
||||
set_workspace_names (screen);
|
||||
@ -787,6 +797,8 @@ meta_screen_init_workspaces (MetaScreen *screen)
|
||||
|
||||
if (current_workspace != NULL)
|
||||
meta_workspace_activate (current_workspace, timestamp);
|
||||
else
|
||||
meta_workspace_activate (screen->workspaces->data, timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
@ -799,8 +811,6 @@ meta_screen_free (MetaScreen *screen,
|
||||
|
||||
screen->closing += 1;
|
||||
|
||||
meta_display_grab (display);
|
||||
|
||||
meta_compositor_unmanage (screen->display->compositor);
|
||||
|
||||
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
|
||||
@ -857,9 +867,6 @@ meta_screen_free (MetaScreen *screen,
|
||||
g_free (screen->screen_name);
|
||||
|
||||
g_object_unref (screen);
|
||||
|
||||
XFlush (display->xdisplay);
|
||||
meta_display_ungrab (display);
|
||||
}
|
||||
|
||||
void
|
||||
@ -872,19 +879,20 @@ meta_screen_create_guard_window (MetaScreen *screen)
|
||||
void
|
||||
meta_screen_manage_all_windows (MetaScreen *screen)
|
||||
{
|
||||
MetaStackWindow *_children;
|
||||
MetaStackWindow *children;
|
||||
guint64 *_children;
|
||||
guint64 *children;
|
||||
int n_children, i;
|
||||
|
||||
meta_stack_freeze (screen->stack);
|
||||
meta_stack_tracker_get_stack (screen->stack_tracker, &_children, &n_children);
|
||||
|
||||
/* Copy the stack as it will be modified as part of the loop */
|
||||
children = g_memdup (_children, sizeof (MetaStackWindow) * n_children);
|
||||
children = g_memdup (_children, sizeof (guint64) * n_children);
|
||||
|
||||
for (i = 0; i < n_children; ++i)
|
||||
{
|
||||
meta_window_x11_new (screen->display, children[i].x11.xwindow, TRUE,
|
||||
g_assert (META_STACK_ID_IS_X11 (children[i]));
|
||||
meta_window_x11_new (screen->display, children[i], TRUE,
|
||||
META_COMP_EFFECT_NONE);
|
||||
}
|
||||
|
||||
@ -909,10 +917,6 @@ prefs_changed_callback (MetaPreference pref,
|
||||
meta_display_get_current_time_roundtrip (screen->display);
|
||||
update_num_workspaces (screen, timestamp);
|
||||
}
|
||||
else if (pref == META_PREF_FOCUS_MODE)
|
||||
{
|
||||
update_focus_mode (screen);
|
||||
}
|
||||
else if (pref == META_PREF_WORKSPACE_NAMES)
|
||||
{
|
||||
set_workspace_names (screen);
|
||||
@ -950,75 +954,23 @@ get_screen_name (MetaDisplay *display,
|
||||
return scr;
|
||||
}
|
||||
|
||||
static gint
|
||||
ptrcmp (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
else if (a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
listify_func (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
GSList **listp;
|
||||
|
||||
listp = data;
|
||||
|
||||
*listp = g_slist_prepend (*listp, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_screen_foreach_window:
|
||||
* @screen: a #MetaScreen
|
||||
* @func: function to call for each window
|
||||
* @data: user data to pass to @func
|
||||
*
|
||||
* Calls the specified function for each window on the screen,
|
||||
* ignoring override-redirect windows.
|
||||
*/
|
||||
void
|
||||
meta_screen_foreach_window (MetaScreen *screen,
|
||||
MetaScreenWindowFunc func,
|
||||
gpointer data)
|
||||
meta_screen_foreach_window (MetaScreen *screen,
|
||||
MetaListWindowsFlags flags,
|
||||
MetaScreenWindowFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
GSList *winlist;
|
||||
GSList *tmp;
|
||||
GSList *windows;
|
||||
|
||||
/* If we end up doing this often, just keeping a list
|
||||
* of windows might be sensible.
|
||||
*/
|
||||
|
||||
winlist = NULL;
|
||||
g_hash_table_foreach (screen->display->xids,
|
||||
listify_func,
|
||||
&winlist);
|
||||
windows = meta_display_list_windows (screen->display, flags);
|
||||
|
||||
winlist = g_slist_sort (winlist, ptrcmp);
|
||||
g_slist_foreach (windows, (GFunc) func, data);
|
||||
|
||||
tmp = winlist;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
/* If the next node doesn't contain this window
|
||||
* a second time, delete the window.
|
||||
*/
|
||||
if (tmp->next == NULL ||
|
||||
(tmp->next && tmp->next->data != tmp->data))
|
||||
{
|
||||
MetaWindow *window = tmp->data;
|
||||
|
||||
if (META_IS_WINDOW (window) &&
|
||||
window->screen == screen &&
|
||||
!window->override_redirect)
|
||||
(* func) (screen, window, data);
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
g_slist_free (winlist);
|
||||
g_slist_free (windows);
|
||||
}
|
||||
|
||||
int
|
||||
@ -1043,27 +995,7 @@ MetaWorkspace*
|
||||
meta_screen_get_workspace_by_index (MetaScreen *screen,
|
||||
int idx)
|
||||
{
|
||||
GList *tmp;
|
||||
int i;
|
||||
|
||||
/* should be robust, idx is maybe from an app */
|
||||
if (idx < 0)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
tmp = screen->workspaces;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWorkspace *w = tmp->data;
|
||||
|
||||
if (i == idx)
|
||||
return w;
|
||||
|
||||
++i;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return g_list_nth_data (screen->workspaces, idx);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1137,41 +1069,28 @@ meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace,
|
||||
guint32 timestamp)
|
||||
{
|
||||
GList *l;
|
||||
GList *next;
|
||||
MetaWorkspace *neighbour = NULL;
|
||||
GList *next = NULL;
|
||||
int index;
|
||||
gboolean active_index_changed;
|
||||
int new_num;
|
||||
|
||||
l = screen->workspaces;
|
||||
while (l)
|
||||
{
|
||||
MetaWorkspace *w = l->data;
|
||||
|
||||
if (w == workspace)
|
||||
{
|
||||
if (l->next)
|
||||
next = l->next;
|
||||
|
||||
if (l->prev)
|
||||
neighbour = l->prev->data;
|
||||
else if (l->next)
|
||||
neighbour = l->next->data;
|
||||
else
|
||||
{
|
||||
/* Cannot remove the only workspace! */
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
if (!neighbour)
|
||||
l = g_list_find (screen->workspaces, workspace);
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
next = l->next;
|
||||
|
||||
if (l->prev)
|
||||
neighbour = l->prev->data;
|
||||
else if (l->next)
|
||||
neighbour = l->next->data;
|
||||
else
|
||||
{
|
||||
/* Cannot remove the only workspace! */
|
||||
return;
|
||||
}
|
||||
|
||||
meta_workspace_relocate_windows (workspace, neighbour);
|
||||
|
||||
if (workspace == screen->active_workspace)
|
||||
@ -1196,14 +1115,10 @@ meta_screen_remove_workspace (MetaScreen *screen, MetaWorkspace *workspace,
|
||||
if (active_index_changed)
|
||||
meta_screen_set_active_workspace_hint (screen);
|
||||
|
||||
l = next;
|
||||
while (l)
|
||||
for (l = next; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWorkspace *w = l->data;
|
||||
|
||||
meta_workspace_update_window_hints (w);
|
||||
|
||||
l = l->next;
|
||||
meta_workspace_index_changed (w);
|
||||
}
|
||||
|
||||
meta_screen_queue_workarea_recalc (screen);
|
||||
@ -1263,7 +1178,7 @@ update_num_workspaces (MetaScreen *screen,
|
||||
guint32 timestamp)
|
||||
{
|
||||
int new_num, old_num;
|
||||
GList *tmp;
|
||||
GList *l;
|
||||
int i;
|
||||
GList *extras;
|
||||
MetaWorkspace *last_remaining;
|
||||
@ -1302,10 +1217,9 @@ update_num_workspaces (MetaScreen *screen,
|
||||
last_remaining = NULL;
|
||||
extras = NULL;
|
||||
i = 0;
|
||||
tmp = screen->workspaces;
|
||||
while (tmp != NULL)
|
||||
for (l = screen->workspaces; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWorkspace *w = tmp->data;
|
||||
MetaWorkspace *w = l->data;
|
||||
|
||||
if (i >= new_num)
|
||||
extras = g_list_prepend (extras, w);
|
||||
@ -1313,7 +1227,6 @@ update_num_workspaces (MetaScreen *screen,
|
||||
last_remaining = w;
|
||||
|
||||
++i;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
old_num = i;
|
||||
|
||||
@ -1326,32 +1239,26 @@ update_num_workspaces (MetaScreen *screen,
|
||||
* is on a removed workspace ;-)
|
||||
*/
|
||||
need_change_space = FALSE;
|
||||
tmp = extras;
|
||||
while (tmp != NULL)
|
||||
for (l = extras; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWorkspace *w = tmp->data;
|
||||
MetaWorkspace *w = l->data;
|
||||
|
||||
meta_workspace_relocate_windows (w, last_remaining);
|
||||
|
||||
if (w == screen->active_workspace)
|
||||
need_change_space = TRUE;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (need_change_space)
|
||||
meta_workspace_activate (last_remaining, timestamp);
|
||||
|
||||
/* Should now be safe to free the workspaces */
|
||||
tmp = extras;
|
||||
while (tmp != NULL)
|
||||
for (l = extras; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWorkspace *w = tmp->data;
|
||||
MetaWorkspace *w = l->data;
|
||||
|
||||
g_assert (w->windows == NULL);
|
||||
meta_workspace_remove (w);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_list_free (extras);
|
||||
@ -1369,12 +1276,6 @@ update_num_workspaces (MetaScreen *screen,
|
||||
g_object_notify (G_OBJECT (screen), "n-workspaces");
|
||||
}
|
||||
|
||||
static void
|
||||
update_focus_mode (MetaScreen *screen)
|
||||
{
|
||||
/* nothing to do anymore */ ;
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_update_cursor (MetaScreen *screen)
|
||||
{
|
||||
@ -2099,31 +2000,25 @@ static void
|
||||
set_work_area_hint (MetaScreen *screen)
|
||||
{
|
||||
int num_workspaces;
|
||||
GList *tmp_list;
|
||||
GList *l;
|
||||
unsigned long *data, *tmp;
|
||||
MetaRectangle area;
|
||||
|
||||
num_workspaces = meta_screen_get_n_workspaces (screen);
|
||||
data = g_new (unsigned long, num_workspaces * 4);
|
||||
tmp_list = screen->workspaces;
|
||||
tmp = data;
|
||||
|
||||
while (tmp_list != NULL)
|
||||
for (l = screen->workspaces; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWorkspace *workspace = tmp_list->data;
|
||||
MetaWorkspace *workspace = l->data;
|
||||
|
||||
if (workspace->screen == screen)
|
||||
{
|
||||
meta_workspace_get_work_area_all_monitors (workspace, &area);
|
||||
tmp[0] = area.x;
|
||||
tmp[1] = area.y;
|
||||
tmp[2] = area.width;
|
||||
tmp[3] = area.height;
|
||||
meta_workspace_get_work_area_all_monitors (workspace, &area);
|
||||
tmp[0] = area.x;
|
||||
tmp[1] = area.y;
|
||||
tmp[2] = area.width;
|
||||
tmp[3] = area.height;
|
||||
|
||||
tmp += 4;
|
||||
}
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
tmp += 4;
|
||||
}
|
||||
|
||||
meta_error_trap_push (screen->display);
|
||||
@ -2463,9 +2358,8 @@ meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_resize_func (MetaScreen *screen,
|
||||
MetaWindow *window,
|
||||
void *user_data)
|
||||
meta_screen_resize_func (MetaWindow *window,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (window->struts)
|
||||
{
|
||||
@ -2480,8 +2374,6 @@ static void
|
||||
on_monitors_changed (MetaMonitorManager *manager,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
GSList *tmp, *windows;
|
||||
|
||||
meta_monitor_manager_get_screen_size (manager,
|
||||
&screen->rect.width,
|
||||
&screen->rect.height);
|
||||
@ -2505,24 +2397,11 @@ on_monitors_changed (MetaMonitorManager *manager,
|
||||
&changes);
|
||||
}
|
||||
|
||||
meta_compositor_sync_screen_size (screen->display->compositor,
|
||||
screen->rect.width, screen->rect.height);
|
||||
|
||||
/* Queue a resize on all the windows */
|
||||
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
|
||||
meta_screen_foreach_window (screen, META_LIST_DEFAULT, meta_screen_resize_func, 0);
|
||||
|
||||
/* Fix up monitor for all windows on this screen */
|
||||
windows = meta_display_list_windows (screen->display,
|
||||
META_LIST_INCLUDE_OVERRIDE_REDIRECT);
|
||||
for (tmp = windows; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
MetaWindow *window = tmp->data;
|
||||
|
||||
if (window->screen == screen)
|
||||
meta_window_update_for_monitors_changed (window);
|
||||
}
|
||||
|
||||
g_slist_free (windows);
|
||||
meta_screen_foreach_window (screen, META_LIST_INCLUDE_OVERRIDE_REDIRECT, (MetaScreenWindowFunc) meta_window_update_for_monitors_changed, 0);
|
||||
|
||||
meta_screen_queue_check_fullscreen (screen);
|
||||
|
||||
@ -2547,8 +2426,7 @@ meta_screen_update_showing_desktop_hint (MetaScreen *screen)
|
||||
static void
|
||||
queue_windows_showing (MetaScreen *screen)
|
||||
{
|
||||
GSList *windows;
|
||||
GSList *tmp;
|
||||
GSList *windows, *l;
|
||||
|
||||
/* Must operate on all windows on display instead of just on the
|
||||
* active_workspace's window list, because the active_workspace's
|
||||
@ -2556,15 +2434,10 @@ queue_windows_showing (MetaScreen *screen)
|
||||
*/
|
||||
windows = meta_display_list_windows (screen->display, META_LIST_DEFAULT);
|
||||
|
||||
tmp = windows;
|
||||
while (tmp != NULL)
|
||||
for (l = windows; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
|
||||
if (w->screen == screen)
|
||||
meta_window_queue (w, META_QUEUE_CALC_SHOWING);
|
||||
|
||||
tmp = tmp->next;
|
||||
MetaWindow *w = l->data;
|
||||
meta_window_queue (w, META_QUEUE_CALC_SHOWING);
|
||||
}
|
||||
|
||||
g_slist_free (windows);
|
||||
@ -2574,22 +2447,14 @@ void
|
||||
meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
|
||||
MetaWindow *keep)
|
||||
{
|
||||
GList *windows;
|
||||
GList *tmp;
|
||||
GList *l;
|
||||
|
||||
windows = screen->active_workspace->windows;
|
||||
|
||||
tmp = windows;
|
||||
while (tmp != NULL)
|
||||
for (l = screen->active_workspace->windows; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
MetaWindow *w = l->data;
|
||||
|
||||
if (w->screen == screen &&
|
||||
w->has_minimize_func &&
|
||||
w != keep)
|
||||
if (w->has_minimize_func && w != keep)
|
||||
meta_window_minimize (w);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2597,7 +2462,7 @@ void
|
||||
meta_screen_show_desktop (MetaScreen *screen,
|
||||
guint32 timestamp)
|
||||
{
|
||||
GList *windows;
|
||||
GList *l;
|
||||
|
||||
if (screen->active_workspace->showing_desktop)
|
||||
return;
|
||||
@ -2609,22 +2474,17 @@ meta_screen_show_desktop (MetaScreen *screen,
|
||||
/* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
|
||||
* see bug 159257.
|
||||
*/
|
||||
windows = screen->active_workspace->mru_list;
|
||||
while (windows != NULL)
|
||||
for (l = screen->active_workspace->mru_list; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWindow *w = windows->data;
|
||||
MetaWindow *w = l->data;
|
||||
|
||||
if (w->screen == screen &&
|
||||
w->type == META_WINDOW_DESKTOP)
|
||||
if (w->type == META_WINDOW_DESKTOP)
|
||||
{
|
||||
meta_window_focus (w, timestamp);
|
||||
break;
|
||||
}
|
||||
|
||||
windows = windows->next;
|
||||
}
|
||||
|
||||
|
||||
meta_screen_update_showing_desktop_hint (screen);
|
||||
}
|
||||
|
||||
@ -2753,7 +2613,7 @@ startup_sequence_timeout (void *data)
|
||||
{
|
||||
MetaScreen *screen = data;
|
||||
CollectTimedOutData ctod;
|
||||
GSList *tmp;
|
||||
GSList *l;
|
||||
|
||||
ctod.list = NULL;
|
||||
g_get_current_time (&ctod.now);
|
||||
@ -2761,18 +2621,15 @@ startup_sequence_timeout (void *data)
|
||||
collect_timed_out_foreach,
|
||||
&ctod);
|
||||
|
||||
tmp = ctod.list;
|
||||
while (tmp != NULL)
|
||||
for (l = ctod.list; l != NULL; l = l->next)
|
||||
{
|
||||
SnStartupSequence *sequence = tmp->data;
|
||||
SnStartupSequence *sequence = l->data;
|
||||
|
||||
meta_topic (META_DEBUG_STARTUP,
|
||||
"Timed out sequence %s\n",
|
||||
sn_startup_sequence_get_id (sequence));
|
||||
|
||||
sn_startup_sequence_complete (sequence);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_slist_free (ctod.list);
|
||||
@ -2873,7 +2730,7 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
|
||||
{
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
const char *startup_id;
|
||||
GSList *tmp;
|
||||
GSList *l;
|
||||
SnStartupSequence *sequence;
|
||||
|
||||
/* Does the window have a startup ID stored? */
|
||||
@ -2891,12 +2748,12 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
|
||||
* startup-notification library whether there's anything
|
||||
* stored for the resource name or resource class hints.
|
||||
*/
|
||||
tmp = screen->startup_sequences;
|
||||
while (tmp != NULL)
|
||||
for (l = screen->startup_sequences; l != NULL; l = l->next)
|
||||
{
|
||||
const char *wmclass;
|
||||
SnStartupSequence *seq = l->data;
|
||||
|
||||
wmclass = sn_startup_sequence_get_wmclass (tmp->data);
|
||||
wmclass = sn_startup_sequence_get_wmclass (seq);
|
||||
|
||||
if (wmclass != NULL &&
|
||||
((window->res_class &&
|
||||
@ -2904,7 +2761,7 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
|
||||
(window->res_name &&
|
||||
strcmp (wmclass, window->res_name) == 0)))
|
||||
{
|
||||
sequence = tmp->data;
|
||||
sequence = seq;
|
||||
|
||||
g_assert (window->startup_id == NULL);
|
||||
window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence));
|
||||
@ -2918,8 +2775,6 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
|
||||
sn_startup_sequence_complete (sequence);
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2933,20 +2788,18 @@ meta_screen_apply_startup_properties (MetaScreen *screen,
|
||||
*/
|
||||
if (sequence == NULL)
|
||||
{
|
||||
tmp = screen->startup_sequences;
|
||||
while (tmp != NULL)
|
||||
for (l = screen->startup_sequences; l != NULL; l = l->next)
|
||||
{
|
||||
SnStartupSequence *seq = l->data;
|
||||
const char *id;
|
||||
|
||||
id = sn_startup_sequence_get_id (tmp->data);
|
||||
id = sn_startup_sequence_get_id (seq);
|
||||
|
||||
if (strcmp (id, startup_id) == 0)
|
||||
{
|
||||
sequence = tmp->data;
|
||||
sequence = seq;
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user