Compare commits
212 Commits
3.9.1
...
wip/waylan
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ef00e3fc0b | ||
![]() |
e0df9eee28 | ||
![]() |
4492845528 | ||
![]() |
c334fd5288 | ||
![]() |
83f61daf95 | ||
![]() |
a474608954 | ||
![]() |
67457dc25c | ||
![]() |
9cff36bf30 | ||
![]() |
8708d038be | ||
![]() |
f59d92a246 | ||
![]() |
b7983201d7 | ||
![]() |
99a6a1f881 | ||
![]() |
3b3c6d08b6 | ||
![]() |
26f452d522 | ||
![]() |
76fccc069d | ||
![]() |
156365b609 | ||
![]() |
bd6536dec3 | ||
![]() |
b53bf0e8c2 | ||
![]() |
a26ded47d9 | ||
![]() |
cad9e14463 | ||
![]() |
806d5939e3 | ||
![]() |
0f0c23fbab | ||
![]() |
5d1fcc26c0 | ||
![]() |
cbe5b6b3bc | ||
![]() |
590cf4e832 | ||
![]() |
22ca820c44 | ||
![]() |
b1206ceb66 | ||
![]() |
ad4053ab84 | ||
![]() |
7bd4e6ecb0 | ||
![]() |
deeb1db1ac | ||
![]() |
7eb4bfbea3 | ||
![]() |
59b274f12f | ||
![]() |
e311cef013 | ||
![]() |
e72f81c24f | ||
![]() |
96fa518576 | ||
![]() |
e263b3624c | ||
![]() |
1c34f0b342 | ||
![]() |
2d27873f98 | ||
![]() |
fd40a12213 | ||
![]() |
57406e0a9e | ||
![]() |
1987cbb764 | ||
![]() |
705978405b | ||
![]() |
daba05f6a7 | ||
![]() |
1a7984be43 | ||
![]() |
1b3c77d53a | ||
![]() |
5b0f0d9e5b | ||
![]() |
9816659fa9 | ||
![]() |
3b1b611634 | ||
![]() |
f08921bd0c | ||
![]() |
0089b5769c | ||
![]() |
452be05ea0 | ||
![]() |
69f038f7c7 | ||
![]() |
2d35e07fae | ||
![]() |
95e2d26d03 | ||
![]() |
f506e090ea | ||
![]() |
0697b53826 | ||
![]() |
7d9141c56f | ||
![]() |
519a06b93d | ||
![]() |
0cceddab75 | ||
![]() |
c9830c13b4 | ||
![]() |
9a4783e364 | ||
![]() |
aa15c09d54 | ||
![]() |
62d908be42 | ||
![]() |
6526e9882b | ||
![]() |
ab72352c47 | ||
![]() |
f09b9573f0 | ||
![]() |
3d3ae40f79 | ||
![]() |
ea3d2b4759 | ||
![]() |
542a0886cf | ||
![]() |
bd3d5df9ce | ||
![]() |
91cdfab495 | ||
![]() |
1617323dca | ||
![]() |
bbf9358eba | ||
![]() |
9682a2aea4 | ||
![]() |
c9fbb51775 | ||
![]() |
aa6d887214 | ||
![]() |
13312527de | ||
![]() |
9bd366f2a6 | ||
![]() |
5de346bfef | ||
![]() |
2af20b77b6 | ||
![]() |
9affbf10a6 | ||
![]() |
c0acf3ae6d | ||
![]() |
2c1b20e15f | ||
![]() |
77290b6736 | ||
![]() |
876f81db12 | ||
![]() |
75f3ae14b5 | ||
![]() |
d26f248b0f | ||
![]() |
eeb3dfc991 | ||
![]() |
e66db2eab3 | ||
![]() |
2ae7454f36 | ||
![]() |
4fd3c63da9 | ||
![]() |
909a6607c5 | ||
![]() |
1bde397edf | ||
![]() |
015c05fbf6 | ||
![]() |
8ad5ccd2f8 | ||
![]() |
115cc870c7 | ||
![]() |
3112794d83 | ||
![]() |
3528b067d0 | ||
![]() |
0986b660be | ||
![]() |
3bb5086173 | ||
![]() |
69467842ab | ||
![]() |
57077435ed | ||
![]() |
46de0ed462 | ||
![]() |
5086626805 | ||
![]() |
bbbcd8c631 | ||
![]() |
3b61b85f2c | ||
![]() |
cd20f1bc0b | ||
![]() |
8b52782ed4 | ||
![]() |
849050be95 | ||
![]() |
5c27a91684 | ||
![]() |
764c472edb | ||
![]() |
d0529b7482 | ||
![]() |
8f4621240a | ||
![]() |
e039add240 | ||
![]() |
dbd8d4d598 | ||
![]() |
522542c486 | ||
![]() |
fc67c707e4 | ||
![]() |
c354e7e81b | ||
![]() |
bf40409d97 | ||
![]() |
57d083730e | ||
![]() |
dc242e46c2 | ||
![]() |
7e1d1003c9 | ||
![]() |
3bb33d384f | ||
![]() |
214f31257b | ||
![]() |
bfc87d13cb | ||
![]() |
506ddc3d6c | ||
![]() |
24564c77d6 | ||
![]() |
18a21b67c2 | ||
![]() |
3803fd9511 | ||
![]() |
152d896f75 | ||
![]() |
2f3a5f2001 | ||
![]() |
c3e8646af3 | ||
![]() |
8c17b670fb | ||
![]() |
0e098249b1 | ||
![]() |
12d2e1f600 | ||
![]() |
c20b007985 | ||
![]() |
ef480e9120 | ||
![]() |
8c1c77482d | ||
![]() |
e633606ca9 | ||
![]() |
9a5f243f73 | ||
![]() |
03f55b9485 | ||
![]() |
ef9ef87d91 | ||
![]() |
0ee2c21da7 | ||
![]() |
9b966561c4 | ||
![]() |
8c0779a9db | ||
![]() |
2c901cc015 | ||
![]() |
85e66f69fa | ||
![]() |
a5585327dc | ||
![]() |
268ebb1b18 | ||
![]() |
40e820f551 | ||
![]() |
f9a11b3b18 | ||
![]() |
bd3c357212 | ||
![]() |
b4d108dac6 | ||
![]() |
6585a5760b | ||
![]() |
531be6c413 | ||
![]() |
f0c503b5a9 | ||
![]() |
6fdc23d0b7 | ||
![]() |
4862872c78 | ||
![]() |
ae2e4c5114 | ||
![]() |
06b5be2d13 | ||
![]() |
56fb8a81b3 | ||
![]() |
90a3d613ca | ||
![]() |
c2af13cf31 | ||
![]() |
b0cf0b2442 | ||
![]() |
1c569c2d0e | ||
![]() |
e3855c77af | ||
![]() |
21fe5be026 | ||
![]() |
57bc974a57 | ||
![]() |
3b51405255 | ||
![]() |
73dbb4b9a5 | ||
![]() |
51acc3ee31 | ||
![]() |
a6f206f07c | ||
![]() |
9504fdd2cb | ||
![]() |
b76c3312e9 | ||
![]() |
fd7db8e6b3 | ||
![]() |
b7840bec7d | ||
![]() |
f743539886 | ||
![]() |
15e01152da | ||
![]() |
2103ff6a5c | ||
![]() |
8ab136b7ea | ||
![]() |
5205821fb9 | ||
![]() |
7187206ef5 | ||
![]() |
96221e6c04 | ||
![]() |
7fdfbad6d4 | ||
![]() |
2a5b068863 | ||
![]() |
0c505faded | ||
![]() |
b2dd4f33f7 | ||
![]() |
47b21b3547 | ||
![]() |
c119f98bac | ||
![]() |
d20078574e | ||
![]() |
26bd4fde5c | ||
![]() |
2af49e503f | ||
![]() |
6ea6af6eb4 | ||
![]() |
10df80762c | ||
![]() |
f86032d700 | ||
![]() |
a8eb33f6fd | ||
![]() |
bd19de9429 | ||
![]() |
2ca2838548 | ||
![]() |
df8234c5e3 | ||
![]() |
d03ffd801e | ||
![]() |
7a4c808e43 | ||
![]() |
4f1d62170b | ||
![]() |
e10804727d | ||
![]() |
e430e051b7 | ||
![]() |
696d9d2fa9 | ||
![]() |
f6dd081acd | ||
![]() |
eddd6f8e9b | ||
![]() |
dfa4c7d670 | ||
![]() |
a487d4dd01 | ||
![]() |
c2ecdd0524 | ||
![]() |
50b9042ac2 | ||
![]() |
f5e75de330 |
21
.gitignore
vendored
21
.gitignore
vendored
@@ -23,7 +23,7 @@ src/50-mutter-navigation.xml
|
||||
src/50-mutter-system.xml
|
||||
src/50-mutter-windows.xml
|
||||
src/mutter-wm.desktop
|
||||
src/mutter.desktop
|
||||
src/mutter-wayland.desktop
|
||||
*.o
|
||||
*.a
|
||||
*.lo
|
||||
@@ -46,13 +46,13 @@ POTFILES
|
||||
po/*.pot
|
||||
50-metacity-desktop-key.xml
|
||||
50-metacity-key.xml
|
||||
inlinepixbufs.h
|
||||
libmutter.pc
|
||||
mutter
|
||||
mutter-theme-viewer
|
||||
mutter.desktop
|
||||
libmutter-wayland.pc
|
||||
mutter-wayland
|
||||
mutter-launch
|
||||
org.gnome.mutter.gschema.valid
|
||||
org.gnome.mutter.gschema.xml
|
||||
org.gnome.mutter.wayland.gschema.valid
|
||||
org.gnome.mutter.wayland.gschema.xml
|
||||
testasyncgetprop
|
||||
testboxes
|
||||
testgradient
|
||||
@@ -62,6 +62,7 @@ mutter-message
|
||||
mutter-window-demo
|
||||
focus-window
|
||||
test-attached
|
||||
test-focus
|
||||
test-gravity
|
||||
test-resizing
|
||||
test-size-hints
|
||||
@@ -74,7 +75,15 @@ src/mutter-enum-types.[ch]
|
||||
src/stamp-mutter-enum-types.h
|
||||
src/mutter-marshal.[ch]
|
||||
src/stamp-mutter-marshal.h
|
||||
src/meta-dbus-xrandr.[ch]
|
||||
src/meta-dbus-idle-monitor.[ch]
|
||||
src/mutter-plugins.pc
|
||||
src/wayland/gtk-shell-protocol.c
|
||||
src/wayland/gtk-shell-client-protocol.h
|
||||
src/wayland/gtk-shell-server-protocol.h
|
||||
src/wayland/xserver-protocol.c
|
||||
src/wayland/xserver-client-protocol.h
|
||||
src/wayland/xserver-server-protocol.h
|
||||
doc/reference/*.args
|
||||
doc/reference/*.bak
|
||||
doc/reference/*.hierarchy
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
SUBDIRS=src po doc
|
||||
SUBDIRS=src protocol data po doc
|
||||
|
||||
EXTRA_DIST = HACKING MAINTAINERS rationales.txt
|
||||
|
||||
|
77
NEWS
77
NEWS
@@ -1,3 +1,80 @@
|
||||
3.9.90
|
||||
======
|
||||
* First release from the wayland branch, includes basic support for running
|
||||
as a wayland compositor [Robert, Neil, Giovanni]
|
||||
* Add support for _GTK_FRAME_EXTENTS [Jasper; #705766]
|
||||
* Fix quick consecutive <super> presses breaking keyboard input [Alban; #666101]
|
||||
* Work towards running as wayland compositor [Giovanni]
|
||||
- Add DBus API for display configuration
|
||||
[#705670, #706231, #706233, #706322, #706382]
|
||||
- Add abstraction layer for cursor tracking [#705911]
|
||||
- Add support for plugin modality under wayland [#705917]
|
||||
* Disable GTK+ scaling [Alexander; #706388]
|
||||
* Disable blending while updating tower [Robert]
|
||||
* Misc bug fixes and cleanups [Adel, Jasper, Giovanni, Colin, Rico, Florian;
|
||||
#703332, #704437, #706207]
|
||||
|
||||
Contributors:
|
||||
Robert Bragg, Giovanni Campagna, Alban Crequy, Adel Gadllah,
|
||||
Alexander Larsson, Florian Müllner, Jasper St. Pierre, Neil Roberts,
|
||||
Rico Tzschichholz, Colin Walters
|
||||
|
||||
Translations:
|
||||
Jiro Matsuzawa [ja], Kjartan Maraas [nb], Matej Urbančič [sl],
|
||||
Marek Černocký [cs], Daniel Mustieles [es], Rafael Ferreira [pt_BR],
|
||||
Yaron Shahrabani [he], Ján Kyselica [sk]
|
||||
|
||||
3.9.5
|
||||
=====
|
||||
* Don't select for touch events on the stage [Jasper; #697192]
|
||||
* Don't queue redraws for obscured regions [Adel; #703332]
|
||||
* Export timestamp of global keybinding events [Bastien; #704858]
|
||||
* Misc bug fixes and cleanups [Jasper, Rico; #703970]
|
||||
|
||||
Contributors:
|
||||
Adel Gadllah, Bastien Nocera, Jasper St. Pierre, Rico Tzschichholz
|
||||
|
||||
3.9.4
|
||||
=====
|
||||
* Tweak window shadows [Allan; #702141]
|
||||
* Ignore our own focus events for focus prediction [Jasper; #701017]
|
||||
* Add API to query if the stage is focused [Jasper; #700735]
|
||||
* Add API to query the monitor for a given position [Adel]
|
||||
* Don't force attached dialogs to be border-only [Florian; #702764]
|
||||
* Allow slicing of backgrounds to avoid texture size limits [Ray; #702283]
|
||||
* Miscellaneous bug fixes and cleanups [Adel; #701224, #702564]
|
||||
|
||||
Contributors:
|
||||
Allan Day, Adel Gadllah, Florian Müllner, Jasper St. Pierre, Ray Strode
|
||||
|
||||
3.9.3
|
||||
=====
|
||||
* Ensure events are always reported to the grab window [Rui; #701219]
|
||||
* Use new clutter_stage_set_paint_callback() function to prevent dropping
|
||||
frames with frame synced toolkits [Owen; #698794]
|
||||
|
||||
Contributors:
|
||||
Rui Matos, Owen W. Taylor
|
||||
|
||||
3.9.2
|
||||
=====
|
||||
* Add meta_window_can_close() function [Jasper; #699269]
|
||||
* Add support for string-array preferences [Florian; #700223]
|
||||
* Fix a potential race condition with _NET_WM_MOVERESIZE [Jasper; #699777]
|
||||
* Fix shade window action [Stef; #693714]
|
||||
* Remove overlay_group [Giovanni; #700735]
|
||||
* Improve tracking of the focus window [Dan, Jasper; #647706]
|
||||
* Add API to freeze/unfreeze the keyboard [Rui; #697001]
|
||||
* Grab and emit a signal when XK_ISO_Next_Group is pressed [Rui; #697002]
|
||||
* Misc bug fixes and cleanups [Dieter, Jasper, Rui; #699636, #700735, #697000]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Rui Matos, Florian Müllner, Jasper St. Pierre,
|
||||
Dieter Verfaillie, Stef Walter, Dan Winship
|
||||
|
||||
Translations:
|
||||
Kjartan Maraas [nb], Ján Kyselica [sk]
|
||||
|
||||
3.9.1
|
||||
=====
|
||||
* Fix miscellaneous memory leaks [Pavel; #698710]
|
||||
|
@@ -5,7 +5,7 @@ srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
PKG_NAME="mutter"
|
||||
REQUIRED_AUTOMAKE_VERSION=1.10
|
||||
REQUIRED_AUTOMAKE_VERSION=1.13
|
||||
|
||||
(test -f $srcdir/configure.ac \
|
||||
&& test -d $srcdir/src) || {
|
||||
|
60
configure.ac
60
configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
|
||||
|
||||
m4_define([mutter_major_version], [3])
|
||||
m4_define([mutter_minor_version], [9])
|
||||
m4_define([mutter_micro_version], [1])
|
||||
m4_define([mutter_micro_version], [91])
|
||||
|
||||
m4_define([mutter_version],
|
||||
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
||||
@@ -15,10 +15,14 @@ AC_INIT([mutter], [mutter_version],
|
||||
AC_CONFIG_SRCDIR(src/core/display.c)
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar])
|
||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar])
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
|
||||
# Change pkglibdir and pkgdatadir to mutter-wayland instead of mutter
|
||||
PACKAGE="mutter-wayland"
|
||||
AC_SUBST([PACKAGE], [$PACKAGE])
|
||||
|
||||
MUTTER_MAJOR_VERSION=mutter_major_version
|
||||
MUTTER_MINOR_VERSION=mutter_minor_version
|
||||
MUTTER_MICRO_VERSION=mutter_micro_version
|
||||
@@ -34,7 +38,7 @@ AC_SUBST(MUTTER_PLUGIN_DIR)
|
||||
# Honor aclocal flags
|
||||
AC_SUBST(ACLOCAL_AMFLAGS, "\${ACLOCAL_FLAGS}")
|
||||
|
||||
GETTEXT_PACKAGE=mutter
|
||||
GETTEXT_PACKAGE=mutter-wayland
|
||||
AC_SUBST(GETTEXT_PACKAGE)
|
||||
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Name of default gettext domain])
|
||||
|
||||
@@ -73,8 +77,10 @@ MUTTER_PC_MODULES="
|
||||
cairo >= 1.10.0
|
||||
gsettings-desktop-schemas >= 3.7.3
|
||||
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
|
||||
$CLUTTER_PACKAGE >= 1.13.5
|
||||
$CLUTTER_PACKAGE >= 1.14.3
|
||||
cogl-1.0 >= 1.13.3
|
||||
upower-glib > 0.9.11
|
||||
gnome-desktop-3.0
|
||||
"
|
||||
|
||||
GLIB_GSETTINGS
|
||||
@@ -113,14 +119,32 @@ AC_ARG_ENABLE(shape,
|
||||
[disable mutter's use of the shaped window extension]),,
|
||||
enable_shape=auto)
|
||||
|
||||
## Wayland support requires the xserver.xml protocol extension found in the weston
|
||||
## repository but since there aren't currently established conventions for
|
||||
## installing and discovering these we simply require a location to be given
|
||||
## explicitly...
|
||||
AC_ARG_WITH([wayland-protocols],
|
||||
[AS_HELP_STRING([--with-wayland-protocols], [Location for wayland extension protocol specs])],
|
||||
[
|
||||
],
|
||||
[])
|
||||
|
||||
AC_ARG_WITH([xwayland-path],
|
||||
[AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])],
|
||||
[XWAYLAND_PATH="$withval"],
|
||||
[XWAYLAND_PATH="$bindir/Xorg"])
|
||||
|
||||
AM_GLIB_GNU_GETTEXT
|
||||
|
||||
## here we get the flags we'll actually use
|
||||
# GRegex requires Glib-2.14.0
|
||||
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
|
||||
# gtk_window_set_icon_name requires gtk2+-2.6.0
|
||||
PKG_CHECK_MODULES(MUTTER_MESSAGE, gtk+-3.0)
|
||||
PKG_CHECK_MODULES(MUTTER_WINDOW_DEMO, gtk+-3.0)
|
||||
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
|
||||
|
||||
saved_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MUTTER_LAUNCH"
|
||||
AC_CHECK_FUNCS([sd_session_get_vt])
|
||||
LIBS="$saved_LIBS"
|
||||
|
||||
# Unconditionally use this dir to avoid a circular dep with gnomecc
|
||||
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
|
||||
@@ -199,6 +223,16 @@ if test x$have_xcursor = xyes; then
|
||||
AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support])
|
||||
fi
|
||||
|
||||
# We always build with wayland enabled
|
||||
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
|
||||
|
||||
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
|
||||
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
||||
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server libdrm"
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||
@@ -307,9 +341,6 @@ if test "x$found_xsync" = "xyes"; then
|
||||
fi
|
||||
|
||||
MUTTER_LIBS="$MUTTER_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
|
||||
MUTTER_MESSAGE_LIBS="$MUTTER_MESSAGE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
|
||||
MUTTER_WINDOW_DEMO_LIBS="$MUTTER_WINDOW_DEMO_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
|
||||
MUTTER_PROPS_LIBS="$MUTTER_PROPS_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
|
||||
|
||||
found_sm=no
|
||||
case "$MUTTER_LIBS" in
|
||||
@@ -439,11 +470,10 @@ doc/man/Makefile
|
||||
doc/reference/Makefile
|
||||
doc/reference/meta-docs.sgml
|
||||
src/Makefile
|
||||
src/wm-tester/Makefile
|
||||
src/libmutter.pc
|
||||
src/mutter-plugins.pc
|
||||
src/tools/Makefile
|
||||
src/libmutter-wayland.pc
|
||||
src/compositor/plugins/Makefile
|
||||
protocol/Makefile
|
||||
data/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
||||
@@ -459,7 +489,7 @@ fi
|
||||
|
||||
dnl ==========================================================================
|
||||
echo "
|
||||
mutter-$VERSION
|
||||
mutter-wayland-$VERSION
|
||||
|
||||
prefix: ${prefix}
|
||||
source code location: ${srcdir}
|
||||
|
3
data/Makefile.am
Normal file
3
data/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
defaultcursordir = $(pkgdatadir)/cursors
|
||||
|
||||
dist_defaultcursor_DATA = left_ptr.png
|
BIN
data/left_ptr.png
Normal file
BIN
data/left_ptr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 736 B |
@@ -140,7 +140,7 @@ expand_content_files= \
|
||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||
GTKDOC_CFLAGS=$(MUTTER_CFLAGS)
|
||||
GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter.la
|
||||
GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter-wayland.la
|
||||
|
||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
@@ -409,7 +409,6 @@ meta_prefs_get_theme
|
||||
meta_prefs_get_titlebar_font
|
||||
meta_prefs_get_num_workspaces
|
||||
meta_prefs_get_dynamic_workspaces
|
||||
meta_prefs_get_application_based
|
||||
meta_prefs_get_disable_workarounds
|
||||
meta_prefs_get_auto_raise
|
||||
meta_prefs_get_auto_raise_delay
|
||||
|
@@ -12,6 +12,7 @@ src/core/display.c
|
||||
src/core/errors.c
|
||||
src/core/keybindings.c
|
||||
src/core/main.c
|
||||
src/core/monitor.c
|
||||
src/core/mutter.c
|
||||
src/core/prefs.c
|
||||
src/core/screen.c
|
||||
@@ -20,15 +21,12 @@ src/core/util.c
|
||||
src/core/window.c
|
||||
src/core/window-props.c
|
||||
src/core/xprops.c
|
||||
src/mutter.desktop.in
|
||||
src/mutter-wm.desktop.in
|
||||
src/mutter-wayland.desktop.in
|
||||
src/org.gnome.mutter.gschema.xml.in
|
||||
src/tools/mutter-message.c
|
||||
src/org.gnome.mutter.wayland.gschema.xml.in
|
||||
src/ui/frames.c
|
||||
src/ui/menu.c
|
||||
src/ui/metaaccellabel.c
|
||||
src/ui/resizepopup.c
|
||||
src/ui/theme.c
|
||||
src/ui/theme-parser.c
|
||||
src/ui/theme-viewer.c
|
||||
|
||||
|
32
po/ja.po
32
po/ja.po
@@ -12,8 +12,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=mutter&keywords=I18N+L10N&component=general\n"
|
||||
"POT-Creation-Date: 2013-03-22 10:02+0000\n"
|
||||
"PO-Revision-Date: 2013-03-25 17:02+0000\n"
|
||||
"POT-Creation-Date: 2013-07-30 12:29+0000\n"
|
||||
"PO-Revision-Date: 2013-07-30 23:01+0900\n"
|
||||
"Last-Translator: Jiro Matsuzawa <jmatsuzawa@gnome.org>\n"
|
||||
"Language-Team: Japanese <gnome-translation@gnome.gr.jp>\n"
|
||||
"Language: ja\n"
|
||||
@@ -133,7 +133,7 @@ msgstr "コマンド実行プロンプトを表示する"
|
||||
|
||||
#: ../src/50-mutter-system.xml.in.h:3
|
||||
msgid "Show the activities overview"
|
||||
msgstr "アクティビティを表示する"
|
||||
msgstr "アクティビティ画面を表示する"
|
||||
|
||||
#: ../src/50-mutter-windows.xml.in.h:1
|
||||
msgid "Windows"
|
||||
@@ -213,12 +213,12 @@ msgstr "画面右半分に表示する"
|
||||
|
||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||
#. * we have no way to get it to exit
|
||||
#: ../src/compositor/compositor.c:568
|
||||
#: ../src/compositor/compositor.c:589
|
||||
#, c-format
|
||||
msgid "Another compositing manager is already running on screen %i on display \"%s\"."
|
||||
msgstr "既に別の合成マネージャーがディスプレイ \"%2$s\" 上のスクリーン %1$i で起動中です"
|
||||
|
||||
#: ../src/compositor/meta-background.c:1191
|
||||
#: ../src/compositor/meta-background.c:1076
|
||||
msgid "background texture could not be created from file"
|
||||
msgstr ""
|
||||
|
||||
@@ -252,22 +252,22 @@ msgstr "待機する(_W)"
|
||||
msgid "_Force Quit"
|
||||
msgstr "強制終了する(_F)"
|
||||
|
||||
#: ../src/core/display.c:401
|
||||
#: ../src/core/display.c:421
|
||||
#, c-format
|
||||
msgid "Missing %s extension required for compositing"
|
||||
msgstr "ウィンドウの合成に必要な %s という拡張モジュールが存在しません"
|
||||
|
||||
#: ../src/core/display.c:493
|
||||
#: ../src/core/display.c:513
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display '%s'\n"
|
||||
msgstr "X Window System のディスプレイ '%s' のオープンに失敗しました\n"
|
||||
|
||||
#: ../src/core/keybindings.c:935
|
||||
#: ../src/core/keybindings.c:1138
|
||||
#, c-format
|
||||
msgid "Some other program is already using the key %s with modifiers %x as a binding\n"
|
||||
msgstr "既にバインディングとして別のプログラムでキー %s (修飾キー %x) を使っています\n"
|
||||
|
||||
#: ../src/core/keybindings.c:1135
|
||||
#: ../src/core/keybindings.c:1335
|
||||
#, fuzzy, c-format
|
||||
msgid "\"%s\" is not a valid accelerator\n"
|
||||
msgstr "\"%s\" はフォーカス属性のためには有効な値ではありません"
|
||||
@@ -328,26 +328,26 @@ msgstr "バージョンを表示する"
|
||||
msgid "Mutter plugin to use"
|
||||
msgstr "使用する Mutter のプラグイン"
|
||||
|
||||
#: ../src/core/prefs.c:1095
|
||||
#: ../src/core/prefs.c:1202
|
||||
msgid "Workarounds for broken applications disabled. Some applications may not behave properly.\n"
|
||||
msgstr "仕様に準拠していないアプリケーションに対する次善策は無効になっています。一部のアプリケーションは正常に動作しない可能性があります\n"
|
||||
|
||||
#: ../src/core/prefs.c:1170
|
||||
#: ../src/core/prefs.c:1277
|
||||
#, c-format
|
||||
msgid "Could not parse font description \"%s\" from GSettings key %s\n"
|
||||
msgstr "GSettings の %2$s キーからフォント名 \"%1$s\" を解析できませんでした\n"
|
||||
|
||||
#: ../src/core/prefs.c:1236
|
||||
#: ../src/core/prefs.c:1343
|
||||
#, c-format
|
||||
msgid "\"%s\" found in configuration database is not a valid value for mouse button modifier\n"
|
||||
msgstr "設定データベース中の \"%s\" はマウスボタンの修飾キーとして妥当な値ではありません\n"
|
||||
|
||||
#: ../src/core/prefs.c:1788
|
||||
#: ../src/core/prefs.c:1909
|
||||
#, c-format
|
||||
msgid "\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"
|
||||
msgstr "設定データベース中の \"%s\" はキーバインド \"%s\" に有効な値ではありません\n"
|
||||
|
||||
#: ../src/core/prefs.c:1887
|
||||
#: ../src/core/prefs.c:1999
|
||||
#, c-format
|
||||
msgid "Workspace %d"
|
||||
msgstr "ワークスペース %d"
|
||||
@@ -465,7 +465,7 @@ msgid "Window manager error: "
|
||||
msgstr "ウィンドウマネージャーのエラー: "
|
||||
|
||||
#. first time through
|
||||
#: ../src/core/window.c:7596
|
||||
#: ../src/core/window.c:7513
|
||||
#, c-format
|
||||
msgid "Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n"
|
||||
msgstr "ウィンドウ %s は ICCCM で指定されていたような WM_CLIENT_LEADER ウィンドウの代わりに自分自身で SM_CLIENT_ID を設定しています\n"
|
||||
@@ -477,7 +477,7 @@ msgstr "ウィンドウ %s は ICCCM で指定されていたような WM_CLIENT
|
||||
#. * MWM but not WM_NORMAL_HINTS are basically broken. We complain
|
||||
#. * about these apps but make them work.
|
||||
#.
|
||||
#: ../src/core/window.c:8320
|
||||
#: ../src/core/window.c:8237
|
||||
#, c-format
|
||||
msgid "Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n"
|
||||
msgstr "ウィンドウ %s はリサイズ可能ではない MWM ヒント指示を設定していますが、最小サイズ %d x %d と最大サイズ %d x %dも設定しています。これはあまり意味がありません\n"
|
||||
|
36
po/nb.po
36
po/nb.po
@@ -4,10 +4,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter 3.8.x\n"
|
||||
"Project-Id-Version: mutter 3.9.x\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-04-03 14:10+0200\n"
|
||||
"PO-Revision-Date: 2013-04-03 14:11+0200\n"
|
||||
"POT-Creation-Date: 2013-08-08 22:14+0200\n"
|
||||
"PO-Revision-Date: 2013-05-28 09:48+0200\n"
|
||||
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
|
||||
"Language-Team: Norwegian bokmål <i18n-no@lister.ping.uio.no>\n"
|
||||
"Language: \n"
|
||||
@@ -205,14 +205,14 @@ msgstr "Visning delt til høyre"
|
||||
|
||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||
#. * we have no way to get it to exit
|
||||
#: ../src/compositor/compositor.c:568
|
||||
#: ../src/compositor/compositor.c:589
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Another compositing manager is already running on screen %i on display \"%s"
|
||||
"\"."
|
||||
msgstr "En annen compositing manager kjører skjerm %i på display «%s»."
|
||||
|
||||
#: ../src/compositor/meta-background.c:1064
|
||||
#: ../src/compositor/meta-background.c:1076
|
||||
msgid "background texture could not be created from file"
|
||||
msgstr "bakgrunnstekstur kunne ikke lages fra fil"
|
||||
|
||||
@@ -250,17 +250,17 @@ msgstr "_Vent"
|
||||
msgid "_Force Quit"
|
||||
msgstr "_Tvungen nedstenging"
|
||||
|
||||
#: ../src/core/display.c:401
|
||||
#: ../src/core/display.c:421
|
||||
#, c-format
|
||||
msgid "Missing %s extension required for compositing"
|
||||
msgstr "Mangler utvidelsen %s som kreves for komposittfunksjon"
|
||||
|
||||
#: ../src/core/display.c:493
|
||||
#: ../src/core/display.c:513
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display '%s'\n"
|
||||
msgstr "Feil under åpning av X Window System skjerm «%s»\n"
|
||||
|
||||
#: ../src/core/keybindings.c:935
|
||||
#: ../src/core/keybindings.c:1138
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Some other program is already using the key %s with modifiers %x as a "
|
||||
@@ -269,7 +269,7 @@ msgstr ""
|
||||
"Et annet program bruker allerede nøkkelen %s med modifikatorer %x som "
|
||||
"binding\n"
|
||||
|
||||
#: ../src/core/keybindings.c:1135
|
||||
#: ../src/core/keybindings.c:1335
|
||||
#, c-format
|
||||
msgid "\"%s\" is not a valid accelerator\n"
|
||||
msgstr "«%s» er ikke en gyldig aksellerator\n"
|
||||
@@ -333,7 +333,7 @@ msgstr "Skriv versjonsnummer"
|
||||
msgid "Mutter plugin to use"
|
||||
msgstr "Mutter-tillegg som skal brukes"
|
||||
|
||||
#: ../src/core/prefs.c:1095
|
||||
#: ../src/core/prefs.c:1202
|
||||
msgid ""
|
||||
"Workarounds for broken applications disabled. Some applications may not "
|
||||
"behave properly.\n"
|
||||
@@ -341,12 +341,12 @@ msgstr ""
|
||||
"Funksjonalitet for å gå rundt ødelagte programmer er deaktivert. Noen "
|
||||
"programmer vil kanskje ikke oppføre seg korrekt.\n"
|
||||
|
||||
#: ../src/core/prefs.c:1170
|
||||
#: ../src/core/prefs.c:1277
|
||||
#, c-format
|
||||
msgid "Could not parse font description \"%s\" from GSettings key %s\n"
|
||||
msgstr "Kunne ikke tolke skriftbeskrivelsen «%s» fra GSettings-nøkkel %s\n"
|
||||
|
||||
#: ../src/core/prefs.c:1236
|
||||
#: ../src/core/prefs.c:1343
|
||||
#, c-format
|
||||
msgid ""
|
||||
"\"%s\" found in configuration database is not a valid value for mouse button "
|
||||
@@ -355,7 +355,7 @@ msgstr ""
|
||||
"«%s» funnet i konfigurasjonsdatabasen er ikke en gyldig verdi for endring av "
|
||||
"musknapp\n"
|
||||
|
||||
#: ../src/core/prefs.c:1788
|
||||
#: ../src/core/prefs.c:1909
|
||||
#, c-format
|
||||
msgid ""
|
||||
"\"%s\" found in configuration database is not a valid value for keybinding "
|
||||
@@ -364,7 +364,7 @@ msgstr ""
|
||||
"«%s» funnet i konfigurasjonsdatabasen er ikke en gyldig verdi for "
|
||||
"tastaturbinding «%s»\n"
|
||||
|
||||
#: ../src/core/prefs.c:1887
|
||||
#: ../src/core/prefs.c:1999
|
||||
#, c-format
|
||||
msgid "Workspace %d"
|
||||
msgstr "Arbeidsområde %d"
|
||||
@@ -492,7 +492,7 @@ msgid "Window manager error: "
|
||||
msgstr "Feil i vindushåndterer: "
|
||||
|
||||
#. first time through
|
||||
#: ../src/core/window.c:7596
|
||||
#: ../src/core/window.c:7513
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER "
|
||||
@@ -508,7 +508,7 @@ msgstr ""
|
||||
#. * MWM but not WM_NORMAL_HINTS are basically broken. We complain
|
||||
#. * about these apps but make them work.
|
||||
#.
|
||||
#: ../src/core/window.c:8320
|
||||
#: ../src/core/window.c:8237
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Window %s sets an MWM hint indicating it isn't resizable, but sets min size "
|
||||
@@ -684,7 +684,9 @@ msgstr "Maksimer vinduer automatisk hvis de er nesten like store som skjermen"
|
||||
msgid ""
|
||||
"If enabled, new windows that are initially the size of the monitor "
|
||||
"automatically get maximized."
|
||||
msgstr "Nye vinduer som i utgangspunktet er samme størrelse som skjermen vil automatisk bli maksimert hvis denne slås på."
|
||||
msgstr ""
|
||||
"Nye vinduer som i utgangspunktet er samme størrelse som skjermen vil "
|
||||
"automatisk bli maksimert hvis denne slås på."
|
||||
|
||||
#: ../src/org.gnome.mutter.gschema.xml.in.h:19
|
||||
msgid "Select window from tab popup"
|
||||
|
1
protocol/Makefile.am
Normal file
1
protocol/Makefile.am
Normal file
@@ -0,0 +1 @@
|
||||
EXTRA_DIST = xserver.xml
|
30
protocol/gtk-shell.xml
Normal file
30
protocol/gtk-shell.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<protocol name="gtk">
|
||||
|
||||
<interface name="gtk_shell" version="1">
|
||||
<enum name="capability">
|
||||
<entry name="global_app_menu" value="1"/>
|
||||
<entry name="global_menu_bar" value="2"/>
|
||||
</enum>
|
||||
|
||||
<event name="capabilities">
|
||||
<arg name="capabilities" type="uint"/>
|
||||
</event>
|
||||
|
||||
<request name="get_gtk_surface">
|
||||
<arg name="gtk_surface" type="new_id" interface="gtk_surface"/>
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="gtk_surface" version="1">
|
||||
<request name="set_dbus_properties">
|
||||
<arg name="application_id" type="string" allow-null="true"/>
|
||||
<arg name="app_menu_path" type="string" allow-null="true"/>
|
||||
<arg name="menubar_path" type="string" allow-null="true"/>
|
||||
<arg name="window_object_path" type="string" allow-null="true"/>
|
||||
<arg name="application_object_path" type="string" allow-null="true"/>
|
||||
<arg name="unique_bus_name" type="string" allow-null="true"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
18
protocol/xserver.xml
Normal file
18
protocol/xserver.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<protocol name="xserver">
|
||||
|
||||
<interface name="xserver" version="1">
|
||||
<request name="set_window_id">
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
<arg name="id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="client">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
|
||||
<event name="listen_socket">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
170
src/Makefile.am
170
src/Makefile.am
@@ -1,15 +1,16 @@
|
||||
# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905
|
||||
.AUTOPARALLEL:
|
||||
|
||||
lib_LTLIBRARIES = libmutter.la
|
||||
lib_LTLIBRARIES = libmutter-wayland.la
|
||||
|
||||
SUBDIRS=wm-tester tools compositor/plugins
|
||||
SUBDIRS=compositor/plugins
|
||||
|
||||
INCLUDES= \
|
||||
-DCLUTTER_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
|
||||
$(MUTTER_CFLAGS) \
|
||||
-I$(top_builddir) \
|
||||
-I$(srcdir) \
|
||||
-I$(srcdir)/core \
|
||||
-I$(srcdir)/ui \
|
||||
@@ -29,11 +30,24 @@ INCLUDES= \
|
||||
-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \
|
||||
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
|
||||
|
||||
mutter_built_sources = \
|
||||
mutter-enum-types.h \
|
||||
mutter-enum-types.c
|
||||
INCLUDES += \
|
||||
-I$(srcdir)/wayland \
|
||||
-I$(builddir)/wayland \
|
||||
-DXWAYLAND_PATH='"@XWAYLAND_PATH@"'
|
||||
|
||||
libmutter_la_SOURCES = \
|
||||
mutter_built_sources = \
|
||||
$(dbus_idle_built_sources) \
|
||||
$(dbus_xrandr_built_sources) \
|
||||
mutter-enum-types.h \
|
||||
mutter-enum-types.c \
|
||||
wayland/gtk-shell-protocol.c \
|
||||
wayland/gtk-shell-server-protocol.h \
|
||||
wayland/gtk-shell-client-protocol.h \
|
||||
wayland/xserver-protocol.c \
|
||||
wayland/xserver-server-protocol.h \
|
||||
wayland/xserver-client-protocol.h
|
||||
|
||||
libmutter_wayland_la_SOURCES = \
|
||||
core/async-getprop.c \
|
||||
core/async-getprop.h \
|
||||
core/barrier.c \
|
||||
@@ -62,6 +76,7 @@ libmutter_la_SOURCES = \
|
||||
compositor/meta-shadow-factory.c \
|
||||
compositor/meta-shadow-factory-private.h \
|
||||
compositor/meta-shaped-texture.c \
|
||||
compositor/meta-shaped-texture-private.h \
|
||||
compositor/meta-texture-rectangle.c \
|
||||
compositor/meta-texture-rectangle.h \
|
||||
compositor/meta-texture-tower.c \
|
||||
@@ -94,6 +109,8 @@ libmutter_la_SOURCES = \
|
||||
ui/draw-workspace.h \
|
||||
core/edge-resistance.c \
|
||||
core/edge-resistance.h \
|
||||
core/edid-parse.c \
|
||||
core/edid.h \
|
||||
core/errors.c \
|
||||
meta/errors.h \
|
||||
core/frame.c \
|
||||
@@ -110,6 +127,16 @@ libmutter_la_SOURCES = \
|
||||
core/keybindings.c \
|
||||
core/keybindings-private.h \
|
||||
core/main.c \
|
||||
core/meta-cursor-tracker.c \
|
||||
core/meta-cursor-tracker-private.h \
|
||||
core/meta-idle-monitor.c \
|
||||
core/meta-idle-monitor-private.h \
|
||||
core/meta-xrandr-shared.h \
|
||||
core/monitor.c \
|
||||
core/monitor-config.c \
|
||||
core/monitor-kms.c \
|
||||
core/monitor-private.h \
|
||||
core/monitor-xrandr.c \
|
||||
core/mutter-Xatomtype.h \
|
||||
core/place.c \
|
||||
core/place.h \
|
||||
@@ -139,7 +166,6 @@ libmutter_la_SOURCES = \
|
||||
meta/common.h \
|
||||
core/core.h \
|
||||
ui/ui.h \
|
||||
inlinepixbufs.h \
|
||||
ui/frames.c \
|
||||
ui/frames.h \
|
||||
ui/menu.c \
|
||||
@@ -157,12 +183,31 @@ libmutter_la_SOURCES = \
|
||||
meta/theme.h \
|
||||
ui/theme-private.h \
|
||||
ui/ui.c \
|
||||
meta/preview-widget.h \
|
||||
ui/preview-widget.c \
|
||||
$(mutter_built_sources)
|
||||
|
||||
libmutter_la_LDFLAGS = -no-undefined
|
||||
libmutter_la_LIBADD = $(MUTTER_LIBS)
|
||||
libmutter_wayland_la_SOURCES += \
|
||||
wayland/meta-wayland.c \
|
||||
wayland/meta-wayland-private.h \
|
||||
wayland/meta-xwayland-private.h \
|
||||
wayland/meta-xwayland.c \
|
||||
wayland/meta-wayland-data-device.c \
|
||||
wayland/meta-wayland-data-device.h \
|
||||
wayland/meta-wayland-keyboard.c \
|
||||
wayland/meta-wayland-keyboard.h \
|
||||
wayland/meta-wayland-pointer.c \
|
||||
wayland/meta-wayland-pointer.h \
|
||||
wayland/meta-wayland-seat.c \
|
||||
wayland/meta-wayland-seat.h \
|
||||
wayland/meta-wayland-stage.h \
|
||||
wayland/meta-wayland-stage.c \
|
||||
wayland/meta-wayland-surface.c \
|
||||
wayland/meta-wayland-surface.h \
|
||||
wayland/meta-wayland-types.h \
|
||||
wayland/meta-weston-launch.c \
|
||||
wayland/meta-weston-launch.h
|
||||
|
||||
libmutter_wayland_la_LDFLAGS = -no-undefined
|
||||
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
|
||||
|
||||
# Headers installed for plugins; introspected information will
|
||||
# be extracted into Mutter-<version>.gir
|
||||
@@ -181,6 +226,8 @@ libmutterinclude_base_headers = \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-background.h \
|
||||
meta/meta-cursor-tracker.h \
|
||||
meta/meta-idle-monitor.h \
|
||||
meta/meta-plugin.h \
|
||||
meta/meta-shaped-texture.h \
|
||||
meta/meta-shadow-factory.h \
|
||||
@@ -196,22 +243,29 @@ libmutterinclude_base_headers = \
|
||||
# Excluded from scanning for introspection but installed
|
||||
# atomnames.h: macros cause problems for scanning process
|
||||
libmutterinclude_extra_headers = \
|
||||
meta/preview-widget.h \
|
||||
meta/atomnames.h
|
||||
|
||||
libmutterincludedir = $(includedir)/mutter/meta
|
||||
libmutterincludedir = $(includedir)/mutter-wayland/meta
|
||||
|
||||
libmutterinclude_HEADERS = \
|
||||
$(libmutterinclude_base_headers) \
|
||||
$(libmutterinclude_extra_headers)
|
||||
|
||||
mutter_theme_viewer_SOURCES= \
|
||||
ui/theme-viewer.c
|
||||
bin_PROGRAMS=mutter-wayland
|
||||
|
||||
bin_PROGRAMS=mutter mutter-theme-viewer
|
||||
mutter_wayland_SOURCES = core/mutter.c
|
||||
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
|
||||
mutter_SOURCES = core/mutter.c
|
||||
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
bin_PROGRAMS+=mutter-launch
|
||||
|
||||
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
|
||||
|
||||
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
|
||||
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
|
||||
|
||||
install-exec-hook:
|
||||
-chown root $(DESTDIR)$(bindir)/mutter-launch
|
||||
-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
include $(INTROSPECTION_MAKEFILE)
|
||||
@@ -233,43 +287,36 @@ typelib_DATA = Meta-$(api_version).typelib
|
||||
|
||||
INTROSPECTION_GIRS = Meta-$(api_version).gir
|
||||
|
||||
Meta-$(api_version).gir: libmutter.la
|
||||
Meta-$(api_version).gir: libmutter-wayland.la
|
||||
@META_GIR@_INCLUDES = GObject-2.0 GDesktopEnums-3.0 Gdk-3.0 Gtk-3.0 Clutter-1.0 xlib-2.0 xfixes-4.0 Cogl-1.0
|
||||
@META_GIR@_EXPORT_PACKAGES = libmutter
|
||||
@META_GIR@_EXPORT_PACKAGES = libmutter-wayland
|
||||
@META_GIR@_CFLAGS = $(INCLUDES)
|
||||
@META_GIR@_LIBS = libmutter.la
|
||||
@META_GIR@_LIBS = libmutter-wayland.la
|
||||
@META_GIR@_FILES = \
|
||||
mutter-enum-types.h \
|
||||
$(libmutterinclude_base_headers) \
|
||||
$(filter %.c,$(libmutter_la_SOURCES))
|
||||
$(filter %.c,$(libmutter_wayland_la_SOURCES))
|
||||
@META_GIR@_SCANNERFLAGS = --warn-all --warn-error
|
||||
|
||||
endif
|
||||
|
||||
mutter_theme_viewer_LDADD= $(MUTTER_LIBS) libmutter.la
|
||||
|
||||
testboxes_SOURCES = core/testboxes.c
|
||||
testgradient_SOURCES = ui/testgradient.c
|
||||
testasyncgetprop_SOURCES = core/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
|
||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
|
||||
@INTLTOOL_DESKTOP_RULE@
|
||||
|
||||
desktopfilesdir=$(datadir)/applications
|
||||
desktopfiles_in_files=mutter.desktop.in
|
||||
desktopfiles_in_files=mutter-wayland.desktop.in
|
||||
desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop)
|
||||
desktopfiles_DATA = $(desktopfiles_files)
|
||||
|
||||
wmpropertiesdir=$(datadir)/gnome/wm-properties
|
||||
wmproperties_in_files=mutter-wm.desktop.in
|
||||
wmproperties_files=$(wmproperties_in_files:.desktop.in=.desktop)
|
||||
wmproperties_DATA = $(wmproperties_files)
|
||||
|
||||
xmldir = @GNOME_KEYBINDINGS_KEYSDIR@
|
||||
xml_in_files = \
|
||||
50-mutter-navigation.xml.in \
|
||||
@@ -277,35 +324,28 @@ xml_in_files = \
|
||||
50-mutter-windows.xml.in
|
||||
xml_DATA = $(xml_in_files:.xml.in=.xml)
|
||||
|
||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
|
||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||
|
||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml
|
||||
@INTLTOOL_XML_NOMERGE_RULE@
|
||||
@GSETTINGS_RULES@
|
||||
|
||||
convertdir = $(datadir)/GConf/gsettings
|
||||
convert_DATA = mutter-schemas.convert
|
||||
|
||||
IMAGES=stock_maximize.png stock_minimize.png stock_delete.png
|
||||
VARIABLES=stock_maximize_data $(srcdir)/stock_maximize.png \
|
||||
stock_minimize_data $(srcdir)/stock_minimize.png \
|
||||
stock_delete_data $(srcdir)/stock_delete.png
|
||||
|
||||
BUILT_SOURCES = inlinepixbufs.h
|
||||
CLEANFILES = \
|
||||
inlinepixbufs.h \
|
||||
mutter.desktop \
|
||||
mutter-wayland.desktop \
|
||||
mutter-wm.desktop \
|
||||
org.gnome.mutter.gschema.xml \
|
||||
org.gnome.mutter.wayland.gschema.xml \
|
||||
$(xml_DATA) \
|
||||
$(mutter_built_sources) \
|
||||
$(typelib_DATA) \
|
||||
$(gir_DATA)
|
||||
|
||||
inlinepixbufs.h: $(IMAGES)
|
||||
$(GDK_PIXBUF_CSOURCE) --raw --build-list $(VARIABLES) >$(srcdir)/inlinepixbufs.h
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
pkgconfig_DATA = libmutter.pc mutter-plugins.pc
|
||||
pkgconfig_DATA = libmutter-wayland.pc
|
||||
|
||||
EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(wmproperties_files) \
|
||||
@@ -314,13 +354,14 @@ EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(wmproperties_in_files) \
|
||||
$(xml_in_files) \
|
||||
org.gnome.mutter.gschema.xml.in \
|
||||
org.gnome.mutter.wayland.gschema.xml.in \
|
||||
mutter-schemas.convert \
|
||||
libmutter.pc.in \
|
||||
mutter-plugins.pc.in \
|
||||
libmutter-wayland.pc.in \
|
||||
mutter-enum-types.h.in \
|
||||
mutter-enum-types.c.in
|
||||
mutter-enum-types.c.in \
|
||||
xrandr.xml idle-monitor.xml
|
||||
|
||||
BUILT_SOURCES += $(mutter_built_sources)
|
||||
BUILT_SOURCES = $(mutter_built_sources)
|
||||
MUTTER_STAMP_FILES = stamp-mutter-enum-types.h
|
||||
CLEANFILES += $(MUTTER_STAMP_FILES)
|
||||
|
||||
@@ -342,3 +383,32 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
|
||||
$(libmutterinclude_base_headers) ) >> xgen-tetc && \
|
||||
cp xgen-tetc mutter-enum-types.c && \
|
||||
rm -f xgen-tetc
|
||||
|
||||
dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
|
||||
|
||||
$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
|
||||
$(AM_V_GEN)gdbus-codegen \
|
||||
--interface-prefix org.gnome.Mutter \
|
||||
--c-namespace MetaDBus \
|
||||
--generate-c-code meta-dbus-xrandr \
|
||||
$(srcdir)/xrandr.xml
|
||||
|
||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||
|
||||
$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
|
||||
$(AM_V_GEN)gdbus-codegen \
|
||||
--interface-prefix org.gnome.Mutter \
|
||||
--c-namespace MetaDBus \
|
||||
--generate-c-code meta-dbus-idle-monitor \
|
||||
--c-generate-object-manager \
|
||||
$(srcdir)/idle-monitor.xml
|
||||
|
||||
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
|
||||
mkdir -p wayland
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
|
||||
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
|
||||
mkdir -p wayland
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
|
||||
wayland/%-client-protocol.h : $(top_builddir)/protocol/%.xml
|
||||
mkdir -p wayland
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
|
||||
|
@@ -66,8 +66,6 @@ void meta_switch_workspace_completed (MetaScreen *screen);
|
||||
|
||||
gboolean meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
Window grab_window,
|
||||
Cursor cursor,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp);
|
||||
void meta_end_modal_for_plugin (MetaScreen *screen,
|
||||
|
@@ -53,17 +53,15 @@
|
||||
*
|
||||
* # Containers #
|
||||
*
|
||||
* There's three containers in the stage that can be used to place actors, here
|
||||
* There's two containers in the stage that are used to place window actors, here
|
||||
* are listed in the order in which they are painted:
|
||||
*
|
||||
* - window group, accessible with meta_get_window_group_for_screen()
|
||||
* - top window group, accessible with meta_get_top_window_group_for_screen()
|
||||
* - overlay group, accessible with meta_get_overlay_group_for_screen()
|
||||
*
|
||||
* Mutter will place actors representing windows in the window group, except for
|
||||
* override-redirect windows (ie. popups and menus) which will be placed in the
|
||||
* top window group. Mutter won't put any actors in the overlay group, but it's
|
||||
* intended for compositors to place there panel, dashes, status bars, etc.
|
||||
* top window group.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@@ -86,6 +84,9 @@
|
||||
#include "meta-window-group.h"
|
||||
#include "window-private.h" /* to check window->hidden */
|
||||
#include "display-private.h" /* for meta_display_lookup_x_window() */
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-wayland-pointer.h"
|
||||
#include "meta-wayland-keyboard.h"
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
@@ -174,7 +175,7 @@ process_damage (MetaCompositor *compositor,
|
||||
if (window_actor == NULL)
|
||||
return;
|
||||
|
||||
meta_window_actor_process_damage (window_actor, event);
|
||||
meta_window_actor_process_x11_damage (window_actor, event);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -255,23 +256,6 @@ meta_get_stage_for_screen (MetaScreen *screen)
|
||||
return info->stage;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_get_overlay_group_for_screen:
|
||||
* @screen: a #MetaScreen
|
||||
*
|
||||
* Returns: (transfer none): The overlay group corresponding to @screen
|
||||
*/
|
||||
ClutterActor *
|
||||
meta_get_overlay_group_for_screen (MetaScreen *screen)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
return info->overlay_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_get_window_group_for_screen:
|
||||
* @screen: a #MetaScreen
|
||||
@@ -346,29 +330,37 @@ void
|
||||
meta_set_stage_input_region (MetaScreen *screen,
|
||||
XserverRegion region)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
/* As a wayland compositor we can simply ignore all this trickery
|
||||
* for setting an input region on the stage for capturing events in
|
||||
* clutter since all input comes to us first and we get to choose
|
||||
* who else sees them.
|
||||
*/
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
|
||||
if (info->stage && info->output)
|
||||
{
|
||||
do_set_stage_input_region (screen, region);
|
||||
if (info->stage && info->output)
|
||||
{
|
||||
do_set_stage_input_region (screen, region);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset info->pending_input_region if one existed before and set the new
|
||||
* one to use it later. */
|
||||
if (info->pending_input_region)
|
||||
{
|
||||
XFixesDestroyRegion (xdpy, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
if (region != None)
|
||||
{
|
||||
info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
|
||||
XFixesCopyRegion (xdpy, info->pending_input_region, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset info->pending_input_region if one existed before and set the new
|
||||
* one to use it later. */
|
||||
if (info->pending_input_region)
|
||||
{
|
||||
XFixesDestroyRegion (xdpy, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
if (region != None)
|
||||
{
|
||||
info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
|
||||
XFixesCopyRegion (xdpy, info->pending_input_region, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -388,28 +380,67 @@ meta_empty_stage_input_region (MetaScreen *screen)
|
||||
meta_set_stage_input_region (screen, region);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
Window grab_window,
|
||||
Cursor cursor,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
void
|
||||
meta_focus_stage_window (MetaScreen *screen,
|
||||
guint32 timestamp)
|
||||
{
|
||||
/* To some extent this duplicates code in meta_display_begin_grab_op(), but there
|
||||
* are significant differences in how we handle grabs that make it difficult to
|
||||
* merge the two.
|
||||
*/
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
gboolean pointer_grabbed = FALSE;
|
||||
gboolean keyboard_grabbed = FALSE;
|
||||
int result;
|
||||
ClutterStage *stage;
|
||||
Window window;
|
||||
|
||||
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
|
||||
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
|
||||
if (!stage)
|
||||
return;
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
window = clutter_x11_get_stage_window (stage);
|
||||
|
||||
if (window == None)
|
||||
return;
|
||||
|
||||
meta_display_set_input_focus_xwindow (screen->display,
|
||||
screen,
|
||||
META_FOCUS_STAGE,
|
||||
window,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_display_set_input_focus_xwindow (screen->display,
|
||||
screen,
|
||||
META_FOCUS_STAGE,
|
||||
None,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_stage_is_focused (MetaScreen *screen)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
|
||||
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
|
||||
if (!stage)
|
||||
return FALSE;
|
||||
|
||||
return (screen->display->focus_type == META_FOCUS_STAGE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
begin_modal_x11 (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
||||
Cursor cursor = None;
|
||||
int result;
|
||||
gboolean pointer_grabbed = FALSE;
|
||||
gboolean keyboard_grabbed = FALSE;
|
||||
|
||||
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
|
||||
{
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
@@ -458,14 +489,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
keyboard_grabbed = TRUE;
|
||||
}
|
||||
|
||||
display->grab_op = META_GRAB_OP_COMPOSITOR;
|
||||
display->grab_window = NULL;
|
||||
display->grab_screen = screen;
|
||||
display->grab_have_pointer = TRUE;
|
||||
display->grab_have_keyboard = TRUE;
|
||||
|
||||
compositor->modal_plugin = plugin;
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
@@ -477,6 +500,80 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
begin_modal_wayland (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWaylandCompositor *compositor;
|
||||
gboolean pointer_grabbed = FALSE;
|
||||
gboolean keyboard_grabbed = FALSE;
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
|
||||
{
|
||||
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
|
||||
goto fail;
|
||||
|
||||
pointer_grabbed = TRUE;
|
||||
}
|
||||
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
|
||||
{
|
||||
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
|
||||
timestamp))
|
||||
goto fail;
|
||||
|
||||
keyboard_grabbed = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
if (pointer_grabbed)
|
||||
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
|
||||
if (keyboard_grabbed)
|
||||
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
{
|
||||
/* To some extent this duplicates code in meta_display_begin_grab_op(), but there
|
||||
* are significant differences in how we handle grabs that make it difficult to
|
||||
* merge the two.
|
||||
*/
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
gboolean ok;
|
||||
|
||||
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
|
||||
return FALSE;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
ok = begin_modal_wayland (screen, plugin, options, timestamp);
|
||||
else
|
||||
ok = begin_modal_x11 (screen, plugin, options, timestamp);
|
||||
if (!ok)
|
||||
return FALSE;
|
||||
|
||||
display->grab_op = META_GRAB_OP_COMPOSITOR;
|
||||
display->grab_window = NULL;
|
||||
display->grab_screen = screen;
|
||||
display->grab_have_pointer = TRUE;
|
||||
display->grab_have_keyboard = TRUE;
|
||||
|
||||
compositor->modal_plugin = plugin;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_end_modal_for_plugin (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
@@ -488,8 +585,19 @@ meta_end_modal_for_plugin (MetaScreen *screen,
|
||||
|
||||
g_return_if_fail (compositor->modal_plugin == plugin);
|
||||
|
||||
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
|
||||
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
|
||||
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
|
||||
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
|
||||
}
|
||||
|
||||
display->grab_op = META_GRAB_OP_NONE;
|
||||
display->grab_window = NULL;
|
||||
@@ -514,20 +622,20 @@ meta_check_end_modal (MetaScreen *screen)
|
||||
{
|
||||
meta_end_modal_for_plugin (screen,
|
||||
compositor->modal_plugin,
|
||||
CurrentTime);
|
||||
|
||||
CurrentTime);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
after_stage_paint (gpointer data)
|
||||
static void
|
||||
after_stage_paint (ClutterStage *stage,
|
||||
gpointer data)
|
||||
{
|
||||
MetaCompScreen *info = (MetaCompScreen*) data;
|
||||
GList *l;
|
||||
|
||||
for (l = info->windows; l; l = l->next)
|
||||
meta_window_actor_post_paint (l->data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -541,6 +649,11 @@ redirect_windows (MetaCompositor *compositor,
|
||||
guint n_retries;
|
||||
guint max_retries;
|
||||
|
||||
/* If we're running with wayland, connected to a headless xwayland
|
||||
* server then all the windows are implicitly redirected offscreen
|
||||
* already and it would generate an error to try and explicitly
|
||||
* redirect them via XCompositeRedirectSubwindows() */
|
||||
|
||||
if (meta_get_replace_current_wm ())
|
||||
max_retries = 5;
|
||||
else
|
||||
@@ -581,8 +694,9 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
MetaCompScreen *info;
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xwin;
|
||||
Window xwin = None;
|
||||
gint width, height;
|
||||
MetaWaylandCompositor *wayland_compositor;
|
||||
|
||||
/* Check if the screen is already managed */
|
||||
if (meta_screen_get_compositor_data (screen))
|
||||
@@ -595,7 +709,14 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
* We have to initialize info->pending_input_region to an empty region explicitly,
|
||||
* because None value is used to mean that the whole screen is an input region.
|
||||
*/
|
||||
info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
|
||||
else
|
||||
{
|
||||
/* Stage input region trickery isn't needed when we're running as a
|
||||
* wayland compositor. */
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
|
||||
info->screen = screen;
|
||||
|
||||
@@ -606,106 +727,132 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
|
||||
meta_screen_set_cm_selection (screen);
|
||||
|
||||
info->stage = clutter_stage_new ();
|
||||
/* We will have already created a stage if running as a wayland
|
||||
* compositor... */
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
wayland_compositor = meta_wayland_compositor_get_default ();
|
||||
info->stage = wayland_compositor->stage;
|
||||
|
||||
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
|
||||
after_stage_paint,
|
||||
info, NULL);
|
||||
meta_screen_get_size (screen, &width, &height);
|
||||
clutter_actor_set_size (info->stage, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->stage = clutter_stage_new ();
|
||||
|
||||
meta_screen_get_size (screen, &width, &height);
|
||||
clutter_actor_realize (info->stage);
|
||||
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
|
||||
{
|
||||
long event_mask;
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
XWindowAttributes attr;
|
||||
|
||||
meta_core_add_old_event_mask (xdisplay, xwin, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XIClearMask (mask.mask, XI_TouchBegin);
|
||||
XIClearMask (mask.mask, XI_TouchEnd);
|
||||
XIClearMask (mask.mask, XI_TouchUpdate);
|
||||
XISelectEvents (xdisplay, xwin, &mask, 1);
|
||||
|
||||
event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask;
|
||||
if (XGetWindowAttributes (xdisplay, xwin, &attr))
|
||||
event_mask |= attr.your_event_mask;
|
||||
|
||||
XSelectInput (xdisplay, xwin, event_mask);
|
||||
}
|
||||
}
|
||||
|
||||
clutter_stage_set_paint_callback (CLUTTER_STAGE (info->stage),
|
||||
after_stage_paint,
|
||||
info,
|
||||
NULL);
|
||||
|
||||
clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY);
|
||||
|
||||
meta_screen_get_size (screen, &width, &height);
|
||||
clutter_actor_realize (info->stage);
|
||||
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
|
||||
{
|
||||
long event_mask;
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
XWindowAttributes attr;
|
||||
|
||||
meta_core_add_old_event_mask (xdisplay, xwin, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XISelectEvents (xdisplay, xwin, &mask, 1);
|
||||
|
||||
event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask;
|
||||
if (XGetWindowAttributes (xdisplay, xwin, &attr))
|
||||
event_mask |= attr.your_event_mask;
|
||||
|
||||
XSelectInput (xdisplay, xwin, event_mask);
|
||||
}
|
||||
|
||||
info->window_group = meta_window_group_new (screen);
|
||||
info->top_window_group = meta_window_group_new (screen);
|
||||
info->overlay_group = clutter_actor_new ();
|
||||
|
||||
clutter_actor_add_child (info->stage, info->window_group);
|
||||
clutter_actor_add_child (info->stage, info->top_window_group);
|
||||
clutter_actor_add_child (info->stage, info->overlay_group);
|
||||
|
||||
info->plugin_mgr = meta_plugin_manager_new (screen);
|
||||
|
||||
/*
|
||||
* Delay the creation of the overlay window as long as we can, to avoid
|
||||
* blanking out the screen. This means that during the plugin loading, the
|
||||
* overlay window is not accessible; if the plugin needs to access it
|
||||
* directly, it should hook into the "show" signal on stage, and do
|
||||
* its stuff there.
|
||||
*/
|
||||
info->output = get_output_window (screen);
|
||||
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
|
||||
|
||||
/* Make sure there isn't any left-over output shape on the
|
||||
* overlay window by setting the whole screen to be an
|
||||
* output region.
|
||||
*
|
||||
* Note: there doesn't seem to be any real chance of that
|
||||
* because the X server will destroy the overlay window
|
||||
* when the last client using it exits.
|
||||
*/
|
||||
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
|
||||
|
||||
do_set_stage_input_region (screen, info->pending_input_region);
|
||||
if (info->pending_input_region != None)
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
XFixesDestroyRegion (xdisplay, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
/* NB: When running as a wayland compositor we don't need an X
|
||||
* composite overlay window, and we don't need to play any input
|
||||
* region tricks to redirect events into clutter. */
|
||||
info->output = None;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Delay the creation of the overlay window as long as we can, to avoid
|
||||
* blanking out the screen. This means that during the plugin loading, the
|
||||
* overlay window is not accessible; if the plugin needs to access it
|
||||
* directly, it should hook into the "show" signal on stage, and do
|
||||
* its stuff there.
|
||||
*/
|
||||
info->output = get_output_window (screen);
|
||||
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
|
||||
|
||||
clutter_actor_show (info->overlay_group);
|
||||
/* Make sure there isn't any left-over output shape on the
|
||||
* overlay window by setting the whole screen to be an
|
||||
* output region.
|
||||
*
|
||||
* Note: there doesn't seem to be any real chance of that
|
||||
* because the X server will destroy the overlay window
|
||||
* when the last client using it exits.
|
||||
*/
|
||||
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
|
||||
|
||||
/* Map overlay window before redirecting windows offscreen so we catch their
|
||||
* contents until we show the stage.
|
||||
*/
|
||||
XMapWindow (xdisplay, info->output);
|
||||
do_set_stage_input_region (screen, info->pending_input_region);
|
||||
if (info->pending_input_region != None)
|
||||
{
|
||||
XFixesDestroyRegion (xdisplay, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
|
||||
redirect_windows (compositor, screen);
|
||||
/* Map overlay window before redirecting windows offscreen so we catch their
|
||||
* contents until we show the stage.
|
||||
*/
|
||||
XMapWindow (xdisplay, info->output);
|
||||
|
||||
redirect_windows (compositor, screen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xroot = meta_screen_get_xroot (screen);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xroot = meta_screen_get_xroot (screen);
|
||||
|
||||
/* This is the most important part of cleanup - we have to do this
|
||||
* before giving up the window manager selection or the next
|
||||
* window manager won't be able to redirect subwindows */
|
||||
XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
|
||||
/* This is the most important part of cleanup - we have to do this
|
||||
* before giving up the window manager selection or the next
|
||||
* window manager won't be able to redirect subwindows */
|
||||
XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -777,15 +924,18 @@ meta_compositor_remove_window (MetaCompositor *compositor,
|
||||
if (!window_actor)
|
||||
return;
|
||||
|
||||
screen = meta_window_get_screen (window);
|
||||
info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (window_actor == info->unredirected_window)
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
meta_window_actor_set_redirected (window_actor, TRUE);
|
||||
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
|
||||
NULL);
|
||||
info->unredirected_window = NULL;
|
||||
screen = meta_window_get_screen (window);
|
||||
info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (window_actor == info->unredirected_window)
|
||||
{
|
||||
meta_window_actor_set_redirected (window_actor, TRUE);
|
||||
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
|
||||
NULL);
|
||||
info->unredirected_window = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
meta_window_actor_destroy (window_actor);
|
||||
@@ -972,7 +1122,8 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
if (!meta_is_wayland_compositor () &&
|
||||
event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
{
|
||||
/* Core code doesn't handle damage events, so we need to extract the MetaWindow
|
||||
* ourselves
|
||||
@@ -991,7 +1142,7 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
|
||||
/* Clutter needs to know about MapNotify events otherwise it will
|
||||
think the stage is invisible */
|
||||
if (event->type == MapNotify)
|
||||
if (!meta_is_wayland_compositor () && event->type == MapNotify)
|
||||
clutter_x11_handle_event (event);
|
||||
|
||||
/* The above handling is basically just "observing" the events, so we return
|
||||
@@ -1335,20 +1486,38 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
Display *xdisplay;
|
||||
Window xwin;
|
||||
|
||||
DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
|
||||
g_return_if_fail (info);
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* FIXME: when we support a sliced stage, this is the place to do it
|
||||
But! This is not the place to apply KMS config, here we only
|
||||
notify Clutter/Cogl/GL that the framebuffer sizes changed.
|
||||
|
||||
xdisplay = meta_display_get_xdisplay (display);
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
||||
And because for now clutter does not do sliced, we use one
|
||||
framebuffer the size of the whole screen, and when running on
|
||||
bare metal MetaMonitorManager will do the necessary tricks to
|
||||
show the right portions on the right screens.
|
||||
*/
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
clutter_actor_set_size (info->stage, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
Display *xdisplay;
|
||||
Window xwin;
|
||||
|
||||
DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
|
||||
g_return_if_fail (info);
|
||||
|
||||
xdisplay = meta_display_get_xdisplay (display);
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
}
|
||||
|
||||
meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
|
||||
meta_screen_get_screen_number (screen),
|
||||
width, height);
|
||||
meta_screen_get_screen_number (screen),
|
||||
width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1412,29 +1581,32 @@ pre_paint_windows (MetaCompScreen *info)
|
||||
if (info->windows == NULL)
|
||||
return;
|
||||
|
||||
top_window = g_list_last (info->windows)->data;
|
||||
|
||||
if (meta_window_actor_should_unredirect (top_window) &&
|
||||
info->disable_unredirect_count == 0)
|
||||
expected_unredirected_window = top_window;
|
||||
|
||||
if (info->unredirected_window != expected_unredirected_window)
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
if (info->unredirected_window != NULL)
|
||||
{
|
||||
meta_window_actor_set_redirected (info->unredirected_window, TRUE);
|
||||
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
|
||||
NULL);
|
||||
}
|
||||
top_window = g_list_last (info->windows)->data;
|
||||
|
||||
if (expected_unredirected_window != NULL)
|
||||
{
|
||||
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)),
|
||||
meta_window_actor_get_meta_window (top_window));
|
||||
meta_window_actor_set_redirected (top_window, FALSE);
|
||||
}
|
||||
if (meta_window_actor_should_unredirect (top_window) &&
|
||||
info->disable_unredirect_count == 0)
|
||||
expected_unredirected_window = top_window;
|
||||
|
||||
info->unredirected_window = expected_unredirected_window;
|
||||
if (info->unredirected_window != expected_unredirected_window)
|
||||
{
|
||||
if (info->unredirected_window != NULL)
|
||||
{
|
||||
meta_window_actor_set_redirected (info->unredirected_window, TRUE);
|
||||
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (info->unredirected_window)),
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (expected_unredirected_window != NULL)
|
||||
{
|
||||
meta_shape_cow_for_window (meta_window_get_screen (meta_window_actor_get_meta_window (top_window)),
|
||||
meta_window_actor_get_meta_window (top_window));
|
||||
meta_window_actor_set_redirected (top_window, FALSE);
|
||||
}
|
||||
|
||||
info->unredirected_window = expected_unredirected_window;
|
||||
}
|
||||
}
|
||||
|
||||
for (l = info->windows; l; l = l->next)
|
||||
@@ -1566,8 +1738,10 @@ void
|
||||
meta_enable_unredirect_for_screen (MetaScreen *screen)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
if (info != NULL)
|
||||
info->disable_unredirect_count = MAX(0, info->disable_unredirect_count - 1);
|
||||
if (info != NULL && info->disable_unredirect_count == 0)
|
||||
g_warning ("Called enable_unredirect_for_screen while unredirection is enabled.");
|
||||
if (info != NULL && info->disable_unredirect_count > 0)
|
||||
info->disable_unredirect_count = info->disable_unredirect_count - 1;
|
||||
}
|
||||
|
||||
#define FLASH_TIME_MS 50
|
||||
|
@@ -6,9 +6,9 @@
|
||||
#include <meta/screen.h>
|
||||
#include <meta/meta-background-actor.h>
|
||||
|
||||
void meta_background_actor_set_visible_region (MetaBackgroundActor *self,
|
||||
cairo_region_t *visible_region);
|
||||
void meta_background_actor_set_clip_region (MetaBackgroundActor *self,
|
||||
cairo_region_t *clip_region);
|
||||
|
||||
cairo_region_t *meta_background_actor_get_visible_region (MetaBackgroundActor *self);
|
||||
cairo_region_t *meta_background_actor_get_clip_region (MetaBackgroundActor *self);
|
||||
|
||||
#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */
|
||||
|
@@ -44,7 +44,7 @@
|
||||
|
||||
struct _MetaBackgroundActorPrivate
|
||||
{
|
||||
cairo_region_t *visible_region;
|
||||
cairo_region_t *clip_region;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
|
||||
@@ -54,7 +54,7 @@ meta_background_actor_dispose (GObject *object)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
|
||||
|
||||
meta_background_actor_set_visible_region (self, NULL);
|
||||
meta_background_actor_set_clip_region (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -167,17 +167,17 @@ meta_background_actor_new (void)
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_actor_set_visible_region:
|
||||
* meta_background_actor_set_clip_region:
|
||||
* @self: a #MetaBackgroundActor
|
||||
* @visible_region: (allow-none): the area of the actor (in allocate-relative
|
||||
* @clip_region: (allow-none): the area of the actor (in allocate-relative
|
||||
* coordinates) that is visible.
|
||||
*
|
||||
* Sets the area of the background that is unobscured by overlapping windows.
|
||||
* This is used to optimize and only paint the visible portions.
|
||||
*/
|
||||
void
|
||||
meta_background_actor_set_visible_region (MetaBackgroundActor *self,
|
||||
cairo_region_t *visible_region)
|
||||
meta_background_actor_set_clip_region (MetaBackgroundActor *self,
|
||||
cairo_region_t *clip_region)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
|
||||
@@ -185,16 +185,16 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self,
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
g_clear_pointer (&priv->visible_region,
|
||||
g_clear_pointer (&priv->clip_region,
|
||||
(GDestroyNotify)
|
||||
cairo_region_destroy);
|
||||
|
||||
if (visible_region)
|
||||
priv->visible_region = cairo_region_copy (visible_region);
|
||||
if (clip_region)
|
||||
priv->clip_region = cairo_region_copy (clip_region);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_actor_get_visible_region:
|
||||
* meta_background_actor_get_clip_region:
|
||||
* @self: a #MetaBackgroundActor
|
||||
*
|
||||
* Return value (transfer full): a #cairo_region_t that represents the part of
|
||||
@@ -202,16 +202,16 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self,
|
||||
* #MetaWindowActor objects.
|
||||
*/
|
||||
cairo_region_t *
|
||||
meta_background_actor_get_visible_region (MetaBackgroundActor *self)
|
||||
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 *visible_region;
|
||||
cairo_region_t *clip_region;
|
||||
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_ACTOR (self), NULL);
|
||||
|
||||
if (!priv->visible_region)
|
||||
if (!priv->clip_region)
|
||||
return NULL;
|
||||
|
||||
clutter_actor_get_content_box (CLUTTER_ACTOR (self), &content_box);
|
||||
@@ -221,8 +221,8 @@ meta_background_actor_get_visible_region (MetaBackgroundActor *self)
|
||||
content_area.width = content_box.x2 - content_box.x1;
|
||||
content_area.height = content_box.y2 - content_box.y1;
|
||||
|
||||
visible_region = cairo_region_create_rectangle (&content_area);
|
||||
cairo_region_intersect (visible_region, priv->visible_region);
|
||||
clip_region = cairo_region_create_rectangle (&content_area);
|
||||
cairo_region_intersect (clip_region, priv->clip_region);
|
||||
|
||||
return visible_region;
|
||||
return clip_region;
|
||||
}
|
||||
|
@@ -6,6 +6,6 @@
|
||||
#include <meta/screen.h>
|
||||
#include <meta/meta-background-group.h>
|
||||
|
||||
void meta_background_group_set_visible_region (MetaBackgroundGroup *self,
|
||||
cairo_region_t *visible_region);
|
||||
void meta_background_group_set_clip_region (MetaBackgroundGroup *self,
|
||||
cairo_region_t *visible_region);
|
||||
#endif /* META_BACKGROUND_GROUP_PRIVATE_H */
|
||||
|
@@ -62,16 +62,16 @@ meta_background_group_init (MetaBackgroundGroup *self)
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_group_set_visible_region:
|
||||
* meta_background_group_set_clip_region:
|
||||
* @self: a #MetaBackgroundGroup
|
||||
* @visible_region: (allow-none): the parts of the background to paint
|
||||
* @region: (allow-none): the parts of the background to paint
|
||||
*
|
||||
* Sets the area of the backgrounds that is unobscured by overlapping windows.
|
||||
* This is used to optimize and only paint the visible portions.
|
||||
*/
|
||||
void
|
||||
meta_background_group_set_visible_region (MetaBackgroundGroup *self,
|
||||
cairo_region_t *region)
|
||||
meta_background_group_set_clip_region (MetaBackgroundGroup *self,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GList *children, *l;
|
||||
|
||||
@@ -82,7 +82,7 @@ meta_background_group_set_visible_region (MetaBackgroundGroup *self,
|
||||
|
||||
if (META_IS_BACKGROUND_ACTOR (actor))
|
||||
{
|
||||
meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (actor), region);
|
||||
meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (actor), region);
|
||||
}
|
||||
else if (META_IS_BACKGROUND_GROUP (actor))
|
||||
{
|
||||
@@ -92,7 +92,7 @@ meta_background_group_set_visible_region (MetaBackgroundGroup *self,
|
||||
continue;
|
||||
|
||||
cairo_region_translate (region, -x, -y);
|
||||
meta_background_group_set_visible_region (META_BACKGROUND_GROUP (actor), region);
|
||||
meta_background_group_set_clip_region (META_BACKGROUND_GROUP (actor), region);
|
||||
cairo_region_translate (region, x, y);
|
||||
}
|
||||
}
|
||||
|
@@ -412,13 +412,13 @@ meta_background_paint_content (ClutterContent *content,
|
||||
*/
|
||||
if (META_IS_BACKGROUND_ACTOR (actor))
|
||||
{
|
||||
cairo_region_t *visible_region;
|
||||
visible_region = meta_background_actor_get_visible_region (META_BACKGROUND_ACTOR (actor));
|
||||
cairo_region_t *clip_region;
|
||||
clip_region = meta_background_actor_get_clip_region (META_BACKGROUND_ACTOR (actor));
|
||||
|
||||
if (visible_region != NULL)
|
||||
if (clip_region != NULL)
|
||||
{
|
||||
cairo_region_intersect (paintable_region, visible_region);
|
||||
cairo_region_destroy (visible_region);
|
||||
cairo_region_intersect (paintable_region, clip_region);
|
||||
cairo_region_destroy (clip_region);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1031,6 @@ meta_background_load_file_finish (MetaBackground *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
static CoglUserDataKey key;
|
||||
GTask *task;
|
||||
LoadFileTaskData *task_data;
|
||||
CoglTexture *texture;
|
||||
@@ -1060,7 +1059,7 @@ meta_background_load_file_finish (MetaBackground *self,
|
||||
|
||||
texture = cogl_texture_new_from_data (width,
|
||||
height,
|
||||
COGL_TEXTURE_NO_SLICING,
|
||||
COGL_TEXTURE_NO_ATLAS,
|
||||
has_alpha ?
|
||||
COGL_PIXEL_FORMAT_RGBA_8888 :
|
||||
COGL_PIXEL_FORMAT_RGB_888,
|
||||
@@ -1077,12 +1076,6 @@ meta_background_load_file_finish (MetaBackground *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (texture),
|
||||
&key,
|
||||
g_object_ref (pixbuf),
|
||||
(CoglUserDataDestroyCallback)
|
||||
g_object_unref);
|
||||
|
||||
ensure_pipeline (self);
|
||||
unset_texture (self);
|
||||
set_style (self, task_data->style);
|
||||
|
@@ -85,12 +85,20 @@ meta_plugin_manager_load (const gchar *plugin_name)
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
on_confirm_display_change (MetaMonitorManager *monitors,
|
||||
MetaPluginManager *plugin_mgr)
|
||||
{
|
||||
meta_plugin_manager_confirm_display_change (plugin_mgr);
|
||||
}
|
||||
|
||||
MetaPluginManager *
|
||||
meta_plugin_manager_new (MetaScreen *screen)
|
||||
{
|
||||
MetaPluginManager *plugin_mgr;
|
||||
MetaPluginClass *klass;
|
||||
MetaPlugin *plugin;
|
||||
MetaMonitorManager *monitors;
|
||||
|
||||
plugin_mgr = g_new0 (MetaPluginManager, 1);
|
||||
plugin_mgr->screen = screen;
|
||||
@@ -101,6 +109,10 @@ meta_plugin_manager_new (MetaScreen *screen)
|
||||
if (klass->start)
|
||||
klass->start (plugin);
|
||||
|
||||
monitors = meta_monitor_manager_get ();
|
||||
g_signal_connect (monitors, "confirm-display-change",
|
||||
G_CALLBACK (on_confirm_display_change), plugin_mgr);
|
||||
|
||||
return plugin_mgr;
|
||||
}
|
||||
|
||||
@@ -317,6 +329,28 @@ meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
|
||||
*/
|
||||
if (klass->xevent_filter)
|
||||
return klass->xevent_filter (plugin, xev);
|
||||
else
|
||||
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
|
||||
|
||||
/* When mutter is running as a wayland compositor, things like input
|
||||
* events just come directly from clutter so it won't have disabled
|
||||
* clutter's event retrieval and won't need to forward it events (if
|
||||
* it did it would lead to recursion). Also when running as a
|
||||
* wayland compositor we shouldn't be assuming that we're running
|
||||
* with the clutter x11 backend.
|
||||
*/
|
||||
if (meta_is_wayland_compositor ())
|
||||
return FALSE;
|
||||
|
||||
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr)
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
|
||||
if (klass->confirm_display_change)
|
||||
return klass->confirm_display_change (plugin);
|
||||
else
|
||||
return meta_plugin_complete_display_change (plugin, TRUE);
|
||||
}
|
||||
|
@@ -73,4 +73,6 @@ gboolean meta_plugin_manager_filter_keybinding (MetaPluginManager *mgr,
|
||||
gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr,
|
||||
XEvent *xev);
|
||||
|
||||
void meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr);
|
||||
|
||||
#endif
|
||||
|
@@ -41,6 +41,7 @@
|
||||
|
||||
#include "compositor-private.h"
|
||||
#include "meta-window-actor-private.h"
|
||||
#include "monitor-private.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
|
||||
|
||||
@@ -266,10 +267,6 @@ meta_plugin_destroy_completed (MetaPlugin *plugin,
|
||||
/**
|
||||
* meta_plugin_begin_modal:
|
||||
* @plugin: a #MetaPlugin
|
||||
* @grab_window: the X window to grab the keyboard and mouse on
|
||||
* @cursor: the cursor to use for the pointer grab, or None,
|
||||
* to use the normal cursor for the grab window and
|
||||
* its descendants.
|
||||
* @options: flags that modify the behavior of the modal grab
|
||||
* @timestamp: the timestamp used for establishing grabs
|
||||
*
|
||||
@@ -290,15 +287,13 @@ meta_plugin_destroy_completed (MetaPlugin *plugin,
|
||||
*/
|
||||
gboolean
|
||||
meta_plugin_begin_modal (MetaPlugin *plugin,
|
||||
Window grab_window,
|
||||
Cursor cursor,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return meta_begin_modal_for_plugin (priv->screen, plugin,
|
||||
grab_window, cursor, options, timestamp);
|
||||
options, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,3 +333,13 @@ meta_plugin_get_screen (MetaPlugin *plugin)
|
||||
|
||||
return priv->screen;
|
||||
}
|
||||
|
||||
void
|
||||
meta_plugin_complete_display_change (MetaPlugin *plugin,
|
||||
gboolean ok)
|
||||
{
|
||||
MetaMonitorManager *manager;
|
||||
|
||||
manager = meta_monitor_manager_get ();
|
||||
meta_monitor_manager_confirm_configuration (manager, ok);
|
||||
}
|
||||
|
@@ -123,12 +123,12 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||
/* The first element in this array also defines the default parameters
|
||||
* for newly created classes */
|
||||
MetaShadowClassInfo default_shadow_classes[] = {
|
||||
{ "normal", { 6, -1, 0, 3, 255 }, { 3, -1, 0, 3, 128 } },
|
||||
{ "dialog", { 6, -1, 0, 3, 255 }, { 3, -1, 0, 3, 128 } },
|
||||
{ "modal_dialog", { 6, -1, 0, 1, 255 }, { 3, -1, 0, 3, 128 } },
|
||||
{ "utility", { 3, -1, 0, 1, 255 }, { 3, -1, 0, 1, 128 } },
|
||||
{ "border", { 6, -1, 0, 3, 255 }, { 3, -1, 0, 3, 128 } },
|
||||
{ "menu", { 6, -1, 0, 3, 255 }, { 3, -1, 0, 0, 128 } },
|
||||
{ "normal", { 6, -1, 0, 3, 128 }, { 3, -1, 0, 3, 32 } },
|
||||
{ "dialog", { 6, -1, 0, 3, 128 }, { 3, -1, 0, 3, 32 } },
|
||||
{ "modal_dialog", { 6, -1, 0, 1, 128 }, { 3, -1, 0, 3, 32 } },
|
||||
{ "utility", { 3, -1, 0, 1, 128 }, { 3, -1, 0, 1, 32 } },
|
||||
{ "border", { 6, -1, 0, 3, 128 }, { 3, -1, 0, 3, 32 } },
|
||||
{ "menu", { 6, -1, 0, 3, 128 }, { 3, -1, 0, 0, 32 } },
|
||||
|
||||
{ "popup-menu", { 1, -1, 0, 1, 128 }, { 1, -1, 0, 1, 128 } },
|
||||
|
||||
|
44
src/compositor/meta-shaped-texture-private.h
Normal file
44
src/compositor/meta-shaped-texture-private.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* shaped texture
|
||||
*
|
||||
* An actor to draw a texture clipped to a list of rectangles
|
||||
*
|
||||
* Authored By Neil Roberts <neil@linux.intel.com>
|
||||
*
|
||||
* Copyright (C) 2008 Intel Corporation
|
||||
* 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __META_SHAPED_TEXTURE_PRIVATE_H__
|
||||
#define __META_SHAPED_TEXTURE_PRIVATE_H__
|
||||
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
ClutterActor *meta_shaped_texture_new_with_xwindow (Window xwindow);
|
||||
ClutterActor *meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface);
|
||||
void meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
|
||||
MetaWaylandSurface *surface);
|
||||
MetaWaylandSurface *meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex);
|
||||
|
||||
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
|
||||
Pixmap pixmap);
|
||||
void meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
|
||||
MetaWaylandBuffer *buffer);
|
||||
|
||||
#endif
|
@@ -30,8 +30,13 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
#include <meta/util.h>
|
||||
#include "meta-texture-tower.h"
|
||||
|
||||
#include "meta-shaped-texture-private.h"
|
||||
#include "meta-wayland-private.h"
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-texture-pixmap-x11.h>
|
||||
@@ -55,6 +60,13 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
|
||||
|
||||
static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
|
||||
|
||||
typedef enum _MetaShapedTextureType
|
||||
{
|
||||
META_SHAPED_TEXTURE_TYPE_X11_PIXMAP,
|
||||
META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE,
|
||||
} MetaShapedTextureType;
|
||||
|
||||
|
||||
G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
|
||||
@@ -65,13 +77,24 @@ G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
|
||||
struct _MetaShapedTexturePrivate
|
||||
{
|
||||
MetaTextureTower *paint_tower;
|
||||
Pixmap pixmap;
|
||||
CoglTexturePixmapX11 *texture;
|
||||
|
||||
MetaShapedTextureType type;
|
||||
union {
|
||||
struct {
|
||||
Pixmap pixmap;
|
||||
} x11;
|
||||
struct {
|
||||
MetaWaylandSurface *surface;
|
||||
} wayland;
|
||||
};
|
||||
|
||||
CoglTexture *texture;
|
||||
|
||||
CoglTexture *mask_texture;
|
||||
CoglPipeline *pipeline;
|
||||
CoglPipeline *pipeline_unshaped;
|
||||
|
||||
cairo_region_t *clip_region;
|
||||
cairo_region_t *input_shape_region;
|
||||
cairo_region_t *opaque_region;
|
||||
|
||||
guint tex_width, tex_height;
|
||||
|
||||
@@ -103,7 +126,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
|
||||
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
|
||||
|
||||
priv->paint_tower = meta_texture_tower_new ();
|
||||
|
||||
priv->type = META_SHAPED_TEXTURE_TYPE_X11_PIXMAP;
|
||||
priv->texture = NULL;
|
||||
|
||||
priv->mask_texture = NULL;
|
||||
priv->create_mipmaps = TRUE;
|
||||
}
|
||||
@@ -118,8 +144,6 @@ meta_shaped_texture_dispose (GObject *object)
|
||||
meta_texture_tower_free (priv->paint_tower);
|
||||
priv->paint_tower = NULL;
|
||||
|
||||
g_clear_pointer (&priv->pipeline, cogl_object_unref);
|
||||
g_clear_pointer (&priv->pipeline_unshaped, cogl_object_unref);
|
||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||
|
||||
meta_shaped_texture_set_mask_texture (self, NULL);
|
||||
@@ -128,19 +152,133 @@ meta_shaped_texture_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static CoglPipeline *
|
||||
get_unmasked_pipeline (CoglContext *ctx)
|
||||
{
|
||||
return cogl_pipeline_new (ctx);
|
||||
}
|
||||
|
||||
static CoglPipeline *
|
||||
get_masked_pipeline (CoglContext *ctx)
|
||||
{
|
||||
static CoglPipeline *template = NULL;
|
||||
if (G_UNLIKELY (template == NULL))
|
||||
{
|
||||
template = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_layer_combine (template, 1,
|
||||
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return cogl_pipeline_copy (template);
|
||||
}
|
||||
|
||||
static CoglPipeline *
|
||||
get_unblended_pipeline (CoglContext *ctx)
|
||||
{
|
||||
static CoglPipeline *template = NULL;
|
||||
if (G_UNLIKELY (template == NULL))
|
||||
{
|
||||
CoglColor color;
|
||||
template = cogl_pipeline_new (ctx);
|
||||
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
|
||||
cogl_pipeline_set_blend (template,
|
||||
"RGBA = ADD (SRC_COLOR, 0)",
|
||||
NULL);
|
||||
cogl_pipeline_set_color (template, &color);
|
||||
}
|
||||
|
||||
return cogl_pipeline_copy (template);
|
||||
}
|
||||
|
||||
static void
|
||||
paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||
CoglPipeline *pipeline,
|
||||
cairo_rectangle_int_t *rect,
|
||||
ClutterActorBox *alloc)
|
||||
{
|
||||
float coords[8];
|
||||
float x1, y1, x2, y2;
|
||||
|
||||
x1 = rect->x;
|
||||
y1 = rect->y;
|
||||
x2 = rect->x + rect->width;
|
||||
y2 = rect->y + rect->height;
|
||||
|
||||
coords[0] = rect->x / (alloc->x2 - alloc->x1);
|
||||
coords[1] = rect->y / (alloc->y2 - alloc->y1);
|
||||
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
|
||||
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
|
||||
|
||||
coords[4] = coords[0];
|
||||
coords[5] = coords[1];
|
||||
coords[6] = coords[2];
|
||||
coords[7] = coords[3];
|
||||
|
||||
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
|
||||
x1, y1, x2, y2,
|
||||
&coords[0], 8);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_cogl_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *cogl_tex)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
guint width, height;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture)
|
||||
cogl_object_unref (priv->texture);
|
||||
|
||||
priv->texture = cogl_object_ref (cogl_tex);
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
{
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (width != priv->tex_width ||
|
||||
height != priv->tex_height)
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* size changed to 0 going to an invalid handle */
|
||||
priv->tex_width = 0;
|
||||
priv->tex_height = 0;
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
/* NB: We don't queue a redraw of the actor here because we don't
|
||||
* know how much of the buffer has changed with respect to the
|
||||
* previous buffer. We only queue a redraw in response to surface
|
||||
* damage. */
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
CoglTexture *paint_tex;
|
||||
guint tex_width, tex_height;
|
||||
guchar opacity;
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *pipeline = NULL;
|
||||
CoglTexture *paint_tex;
|
||||
ClutterActorBox alloc;
|
||||
|
||||
static CoglPipeline *pipeline_template = NULL;
|
||||
static CoglPipeline *pipeline_unshaped_template = NULL;
|
||||
|
||||
CoglPipeline *pipeline;
|
||||
cairo_region_t *blended_region = NULL;
|
||||
|
||||
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
||||
return;
|
||||
@@ -177,38 +315,74 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
||||
return;
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (actor);
|
||||
clutter_actor_get_allocation_box (actor, &alloc);
|
||||
|
||||
if (priv->opaque_region != NULL && opacity == 255)
|
||||
{
|
||||
CoglPipeline *opaque_pipeline;
|
||||
cairo_region_t *region;
|
||||
int n_rects;
|
||||
int i;
|
||||
|
||||
if (priv->clip_region != NULL)
|
||||
{
|
||||
region = cairo_region_copy (priv->clip_region);
|
||||
cairo_region_intersect (region, priv->opaque_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (blended_region != NULL && cairo_region_is_empty (blended_region))
|
||||
goto out;
|
||||
|
||||
if (priv->mask_texture == NULL)
|
||||
{
|
||||
/* Use a single-layer texture if we don't have a mask. */
|
||||
|
||||
if (priv->pipeline_unshaped == NULL)
|
||||
{
|
||||
if (G_UNLIKELY (pipeline_unshaped_template == NULL))
|
||||
{
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
pipeline_unshaped_template = cogl_pipeline_new (ctx);
|
||||
}
|
||||
|
||||
priv->pipeline_unshaped = cogl_pipeline_copy (pipeline_unshaped_template);
|
||||
}
|
||||
pipeline = priv->pipeline_unshaped;
|
||||
pipeline = get_unmasked_pipeline (ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->pipeline == NULL)
|
||||
{
|
||||
if (G_UNLIKELY (pipeline_template == NULL))
|
||||
{
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
pipeline_template = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_layer_combine (pipeline_template, 1,
|
||||
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
||||
NULL);
|
||||
}
|
||||
priv->pipeline = cogl_pipeline_copy (pipeline_template);
|
||||
}
|
||||
pipeline = priv->pipeline;
|
||||
|
||||
pipeline = get_masked_pipeline (ctx);
|
||||
cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
|
||||
}
|
||||
|
||||
@@ -216,66 +390,50 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
|
||||
{
|
||||
CoglColor color;
|
||||
guchar opacity = clutter_actor_get_paint_opacity (actor);
|
||||
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
|
||||
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
||||
cogl_pipeline_set_color (pipeline, &color);
|
||||
}
|
||||
|
||||
cogl_set_source (pipeline);
|
||||
|
||||
clutter_actor_get_allocation_box (actor, &alloc);
|
||||
|
||||
if (priv->clip_region)
|
||||
if (blended_region != NULL)
|
||||
{
|
||||
int n_rects;
|
||||
int i;
|
||||
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
||||
|
||||
/* 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 (priv->clip_region);
|
||||
n_rects = cairo_region_num_rectangles (blended_region);
|
||||
if (n_rects <= MAX_RECTS)
|
||||
{
|
||||
float coords[8];
|
||||
float x1, y1, x2, y2;
|
||||
int i;
|
||||
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
cairo_region_get_rectangle (priv->clip_region, i, &rect);
|
||||
cairo_region_get_rectangle (blended_region, i, &rect);
|
||||
|
||||
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
||||
continue;
|
||||
|
||||
x1 = rect.x;
|
||||
y1 = rect.y;
|
||||
x2 = rect.x + rect.width;
|
||||
y2 = rect.y + rect.height;
|
||||
|
||||
coords[0] = rect.x / (alloc.x2 - alloc.x1);
|
||||
coords[1] = rect.y / (alloc.y2 - alloc.y1);
|
||||
coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
|
||||
coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
|
||||
|
||||
coords[4] = coords[0];
|
||||
coords[5] = coords[1];
|
||||
coords[6] = coords[2];
|
||||
coords[7] = coords[3];
|
||||
|
||||
cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
|
||||
&coords[0], 8);
|
||||
paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
|
||||
}
|
||||
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
cogl_rectangle (0, 0,
|
||||
alloc.x2 - alloc.x1,
|
||||
alloc.y2 - alloc.y1);
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -285,38 +443,61 @@ meta_shaped_texture_pick (ClutterActor *actor,
|
||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
|
||||
if (!clutter_actor_should_pick_paint (actor) ||
|
||||
(priv->clip_region && cairo_region_is_empty (priv->clip_region)))
|
||||
return;
|
||||
|
||||
/* If there is no region then use the regular pick */
|
||||
if (priv->mask_texture == NULL)
|
||||
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
|
||||
->pick (actor, color);
|
||||
else if (clutter_actor_should_pick_paint (actor))
|
||||
if (priv->input_shape_region == NULL)
|
||||
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color);
|
||||
else
|
||||
{
|
||||
CoglTexture *paint_tex;
|
||||
ClutterActorBox alloc;
|
||||
guint tex_width, tex_height;
|
||||
int n_rects;
|
||||
float *rectangles;
|
||||
int i;
|
||||
CoglPipeline *pipeline;
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglColor cogl_color;
|
||||
|
||||
paint_tex = COGL_TEXTURE (priv->texture);
|
||||
/* Note: We don't bother trying to intersect the pick and clip regions
|
||||
* since needing to copy the region, do the intersection, and probably
|
||||
* increase the number of rectangles seems more likely to have a negative
|
||||
* effect.
|
||||
*
|
||||
* NB: Most of the time when just using rectangles for picking then
|
||||
* picking shouldn't involve any rendering, and minimizing the number of
|
||||
* rectangles has more benefit than reducing the area of the pick
|
||||
* region.
|
||||
*/
|
||||
|
||||
if (paint_tex == NULL)
|
||||
return;
|
||||
n_rects = cairo_region_num_rectangles (priv->input_shape_region);
|
||||
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
|
||||
|
||||
tex_width = cogl_texture_get_width (paint_tex);
|
||||
tex_height = cogl_texture_get_height (paint_tex);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
int pos = i * 4;
|
||||
|
||||
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
||||
return;
|
||||
cairo_region_get_rectangle (priv->input_shape_region, i, &rect);
|
||||
|
||||
cogl_set_source_color4ub (color->red, color->green, color->blue,
|
||||
color->alpha);
|
||||
rectangles[pos] = rect.x;
|
||||
rectangles[pos + 1] = rect.y;
|
||||
rectangles[pos + 2] = rect.x + rect.width;
|
||||
rectangles[pos + 3] = rect.y + rect.height;
|
||||
}
|
||||
|
||||
clutter_actor_get_allocation_box (actor, &alloc);
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
/* Paint the mask rectangle in the given color */
|
||||
cogl_set_source_texture (priv->mask_texture);
|
||||
cogl_rectangle_with_texture_coords (0, 0,
|
||||
alloc.x2 - alloc.x1,
|
||||
alloc.y2 - alloc.y1,
|
||||
0, 0, 1, 1);
|
||||
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
|
||||
|
||||
pipeline = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_color (pipeline, &cogl_color);
|
||||
|
||||
cogl_framebuffer_draw_rectangles (fb, pipeline,
|
||||
rectangles, n_rects);
|
||||
cogl_object_unref (pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,11 +547,45 @@ meta_shaped_texture_get_paint_volume (ClutterActor *self,
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
meta_shaped_texture_new (void)
|
||||
meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface)
|
||||
{
|
||||
ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
|
||||
ClutterActor *actor = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
|
||||
MetaShapedTexturePrivate *priv = META_SHAPED_TEXTURE (actor)->priv;
|
||||
|
||||
return self;
|
||||
/* XXX: it could probably be better to have a "type" construct-only
|
||||
* property or create wayland/x11 subclasses */
|
||||
priv->type = META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE;
|
||||
|
||||
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (actor),
|
||||
surface);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
void
|
||||
meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
|
||||
priv->wayland.surface = surface;
|
||||
|
||||
if (surface && surface->buffer_ref.buffer)
|
||||
meta_shaped_texture_attach_wayland_buffer (stex,
|
||||
surface->buffer_ref.buffer);
|
||||
}
|
||||
|
||||
MetaWaylandSurface *
|
||||
meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
return priv->wayland.surface;
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
meta_shaped_texture_new_with_xwindow (Window xwindow)
|
||||
{
|
||||
return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -389,8 +604,7 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
||||
{
|
||||
CoglTexture *base_texture;
|
||||
priv->create_mipmaps = create_mipmaps;
|
||||
base_texture = create_mipmaps ?
|
||||
COGL_TEXTURE (priv->texture) : NULL;
|
||||
base_texture = create_mipmaps ? priv->texture : NULL;
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
|
||||
}
|
||||
}
|
||||
@@ -416,74 +630,190 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
wayland_surface_update_area (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
MetaWaylandBuffer *buffer;
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
g_return_if_fail (priv->type == META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE);
|
||||
g_return_if_fail (priv->texture != NULL);
|
||||
|
||||
buffer = priv->wayland.surface->buffer_ref.buffer;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
struct wl_resource *resource = buffer->resource;
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
|
||||
|
||||
if (shm_buffer)
|
||||
{
|
||||
CoglPixelFormat format;
|
||||
|
||||
switch (wl_shm_buffer_get_format (shm_buffer))
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
|
||||
break;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
break;
|
||||
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
|
||||
break;
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
format = COGL_PIXEL_FORMAT_BGRA_8888;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
}
|
||||
|
||||
cogl_texture_set_region (priv->texture,
|
||||
x, y,
|
||||
x, y,
|
||||
width, height,
|
||||
width, height,
|
||||
format,
|
||||
wl_shm_buffer_get_stride (shm_buffer),
|
||||
wl_shm_buffer_get_data (shm_buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_clip (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
cairo_rectangle_int_t *clip)
|
||||
{
|
||||
ClutterActor *self = CLUTTER_ACTOR (stex);
|
||||
MetaShapedTexturePrivate *priv;
|
||||
ClutterActorBox allocation;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
|
||||
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's
|
||||
* coordinate space so we need to convert from surface coordinates to
|
||||
* actor coordinates...
|
||||
*/
|
||||
|
||||
/* Calling clutter_actor_get_allocation_box() is enormously expensive
|
||||
* if the actor has an out-of-date allocation, since it triggers
|
||||
* a full redraw. clutter_actor_queue_redraw_with_clip() would redraw
|
||||
* the whole stage anyways in that case, so just go ahead and do
|
||||
* it here.
|
||||
*/
|
||||
if (!clutter_actor_has_allocation (self))
|
||||
{
|
||||
clutter_actor_queue_redraw (self);
|
||||
return;
|
||||
}
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->tex_width == 0 || priv->tex_height == 0)
|
||||
return;
|
||||
|
||||
clutter_actor_get_allocation_box (self, &allocation);
|
||||
|
||||
scale_x = (allocation.x2 - allocation.x1) / priv->tex_width;
|
||||
scale_y = (allocation.y2 - allocation.y1) / priv->tex_height;
|
||||
|
||||
clip->x = x * scale_x;
|
||||
clip->y = y * scale_y;
|
||||
clip->width = width * scale_x;
|
||||
clip->height = height * scale_y;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_update_area:
|
||||
* @stex: #MetaShapedTexture
|
||||
* @x: the x coordinate of the damaged area
|
||||
* @y: the y coordinate of the damaged area
|
||||
* @width: the width of the damaged area
|
||||
* @height: the height of the damaged area
|
||||
* @unobscured_region: The unobscured region of the window or %NULL if
|
||||
* there is no valid one (like when the actor is transformed or
|
||||
* has a mapped clone)
|
||||
*
|
||||
* Repairs the damaged area indicated by @x, @y, @width and @height
|
||||
* and queues a redraw for the intersection @visibible_region and
|
||||
* the damage area. If @visibible_region is %NULL a redraw will always
|
||||
* get queued.
|
||||
*
|
||||
* Return value: Whether a redraw have been queued or not
|
||||
*/
|
||||
gboolean
|
||||
meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
int height,
|
||||
cairo_region_t *unobscured_region)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
const cairo_rectangle_int_t clip = { x, y, width, height };
|
||||
cairo_rectangle_int_t clip;
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
cogl_texture_pixmap_x11_update_area (priv->texture,
|
||||
x, y, width, height);
|
||||
switch (priv->type)
|
||||
{
|
||||
case META_SHAPED_TEXTURE_TYPE_X11_PIXMAP:
|
||||
cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (priv->texture),
|
||||
x, y, width, height);
|
||||
break;
|
||||
case META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE:
|
||||
wayland_surface_update_area (stex, x, y, width, height);
|
||||
break;
|
||||
}
|
||||
|
||||
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
|
||||
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
|
||||
}
|
||||
get_clip (stex, x, y, width, height, &clip);
|
||||
|
||||
static void
|
||||
set_cogl_texture (MetaShapedTexture *stex,
|
||||
CoglTexturePixmapX11 *cogl_tex)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
guint width, height;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture != NULL)
|
||||
cogl_object_unref (priv->texture);
|
||||
|
||||
priv->texture = cogl_tex;
|
||||
|
||||
if (priv->pipeline != NULL)
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (priv->pipeline_unshaped != NULL)
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline_unshaped, 0, COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
if (unobscured_region)
|
||||
{
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
||||
cairo_region_t *intersection;
|
||||
|
||||
if (width != priv->tex_width ||
|
||||
height != priv->tex_height)
|
||||
if (cairo_region_is_empty (unobscured_region))
|
||||
return FALSE;
|
||||
|
||||
intersection = cairo_region_copy (unobscured_region);
|
||||
cairo_region_intersect_rectangle (intersection, &clip);
|
||||
|
||||
if (!cairo_region_is_empty (intersection))
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
cairo_rectangle_int_t damage_rect;
|
||||
cairo_region_get_extents (intersection, &damage_rect);
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
|
||||
cairo_region_destroy (intersection);
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* size changed to 0 going to an inavlid texture */
|
||||
priv->tex_width = 0;
|
||||
priv->tex_height = 0;
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
|
||||
cairo_region_destroy (intersection);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -501,16 +831,18 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->pixmap == pixmap)
|
||||
if (priv->x11.pixmap == pixmap)
|
||||
return;
|
||||
|
||||
priv->pixmap = pixmap;
|
||||
priv->x11.pixmap = pixmap;
|
||||
|
||||
if (pixmap != None)
|
||||
{
|
||||
CoglContext *ctx =
|
||||
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
set_cogl_texture (stex, cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
|
||||
CoglTexture *texture =
|
||||
COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
|
||||
set_cogl_texture (stex, texture);
|
||||
}
|
||||
else
|
||||
set_cogl_texture (stex, NULL);
|
||||
@@ -520,6 +852,33 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
|
||||
COGL_TEXTURE (priv->texture));
|
||||
}
|
||||
|
||||
void
|
||||
meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
|
||||
MetaWaylandBuffer *buffer)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
/* TODO: we should change this api to be something like
|
||||
* meta_shaped_texture_notify_buffer_attach() since we now maintain
|
||||
* a reference to the MetaWaylandSurface where we can access the
|
||||
* buffer without it being explicitly passed as an argument.
|
||||
*/
|
||||
g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
|
||||
|
||||
if (buffer)
|
||||
set_cogl_texture (stex, buffer->texture);
|
||||
else
|
||||
set_cogl_texture (stex, NULL);
|
||||
|
||||
if (priv->create_mipmaps)
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower,
|
||||
COGL_TEXTURE (priv->texture));
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_get_texture:
|
||||
* @stex: The #MetaShapedTexture
|
||||
@@ -533,11 +892,46 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex)
|
||||
return COGL_TEXTURE (stex->priv->texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_input_shape_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
* @shape_region: the region of the texture that should respond to
|
||||
* input.
|
||||
*
|
||||
* Determines what region of the texture should accept input. For
|
||||
* X based windows this is defined by the ShapeInput region of the
|
||||
* window.
|
||||
*/
|
||||
void
|
||||
meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *shape_region)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->input_shape_region != NULL)
|
||||
{
|
||||
cairo_region_destroy (priv->input_shape_region);
|
||||
priv->input_shape_region = NULL;
|
||||
}
|
||||
|
||||
if (shape_region != NULL)
|
||||
{
|
||||
cairo_region_reference (shape_region);
|
||||
priv->input_shape_region = shape_region;
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_clip_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
* @clip_region: (transfer full): the region of the texture that
|
||||
* is visible and should be painted.
|
||||
* @clip_region: the region of the texture that is visible and
|
||||
* should be painted.
|
||||
*
|
||||
* Provides a hint to the texture about what areas of the texture
|
||||
* are not completely obscured and thus need to be painted. This
|
||||
@@ -558,10 +952,7 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->clip_region)
|
||||
{
|
||||
cairo_region_destroy (priv->clip_region);
|
||||
priv->clip_region = NULL;
|
||||
}
|
||||
cairo_region_destroy (priv->clip_region);
|
||||
|
||||
if (clip_region)
|
||||
priv->clip_region = cairo_region_copy (clip_region);
|
||||
@@ -569,6 +960,36 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
||||
priv->clip_region = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_opaque_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
* @opaque_region: (transfer full): the region of the texture that
|
||||
* can have blending turned off.
|
||||
*
|
||||
* As most windows have a large portion that does not require blending,
|
||||
* we can easily turn off blending if we know the areas that do not
|
||||
* require blending. This sets the region where we will not blend for
|
||||
* optimization purposes.
|
||||
*/
|
||||
void
|
||||
meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *opaque_region)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->opaque_region)
|
||||
cairo_region_destroy (priv->opaque_region);
|
||||
|
||||
if (opaque_region)
|
||||
priv->opaque_region = cairo_region_reference (opaque_region);
|
||||
else
|
||||
priv->opaque_region = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_get_image:
|
||||
* @stex: A #MetaShapedTexture
|
||||
|
@@ -5,6 +5,9 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include <meta-wayland-private.h>
|
||||
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <meta/compositor-mutter.h>
|
||||
|
||||
@@ -24,8 +27,18 @@ void meta_window_actor_unmaximize (MetaWindowActor *self,
|
||||
MetaRectangle *old_rect,
|
||||
MetaRectangle *new_rect);
|
||||
|
||||
void meta_window_actor_process_damage (MetaWindowActor *self,
|
||||
XDamageNotifyEvent *event);
|
||||
void meta_window_actor_process_x11_damage (MetaWindowActor *self,
|
||||
XDamageNotifyEvent *event);
|
||||
|
||||
void meta_window_actor_process_wayland_damage (MetaWindowActor *self,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
void meta_window_actor_set_wayland_surface (MetaWindowActor *self,
|
||||
MetaWaylandSurface *surface);
|
||||
void meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
|
||||
MetaWaylandBuffer *buffer);
|
||||
|
||||
void meta_window_actor_pre_paint (MetaWindowActor *self);
|
||||
void meta_window_actor_post_paint (MetaWindowActor *self);
|
||||
@@ -57,11 +70,14 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
|
||||
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
|
||||
|
||||
void meta_window_actor_set_visible_region (MetaWindowActor *self,
|
||||
cairo_region_t *visible_region);
|
||||
void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
|
||||
cairo_region_t *beneath_region);
|
||||
void meta_window_actor_reset_visible_regions (MetaWindowActor *self);
|
||||
void meta_window_actor_set_clip_region (MetaWindowActor *self,
|
||||
cairo_region_t *clip_region);
|
||||
void meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
|
||||
cairo_region_t *beneath_region);
|
||||
void meta_window_actor_reset_clip_regions (MetaWindowActor *self);
|
||||
|
||||
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
|
||||
cairo_region_t *unobscured_region);
|
||||
|
||||
void meta_window_actor_effect_completed (MetaWindowActor *actor,
|
||||
gulong event);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@
|
||||
#include "meta-window-group.h"
|
||||
#include "meta-background-actor-private.h"
|
||||
#include "meta-background-group-private.h"
|
||||
#include "window-private.h"
|
||||
|
||||
struct _MetaWindowGroupClass
|
||||
{
|
||||
@@ -89,16 +90,30 @@ painting_untransformed (MetaWindowGroup *window_group,
|
||||
static void
|
||||
meta_window_group_paint (ClutterActor *actor)
|
||||
{
|
||||
cairo_region_t *visible_region;
|
||||
ClutterActor *stage;
|
||||
cairo_rectangle_int_t visible_rect;
|
||||
GList *children, *l;
|
||||
cairo_region_t *clip_region;
|
||||
cairo_region_t *unobscured_region;
|
||||
ClutterActorIter iter;
|
||||
ClutterActor *child;
|
||||
cairo_rectangle_int_t visible_rect, clip_rect;
|
||||
int paint_x_origin, paint_y_origin;
|
||||
int actor_x_origin, actor_y_origin;
|
||||
int paint_x_offset, paint_y_offset;
|
||||
|
||||
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
|
||||
ClutterActor *stage = clutter_actor_get_stage (actor);
|
||||
|
||||
/* Start off by treating all windows as completely unobscured, so damage anywhere
|
||||
* in a window queues redraws, but confine it more below. */
|
||||
clutter_actor_iter_init (&iter, actor);
|
||||
while (clutter_actor_iter_next (&iter, &child))
|
||||
{
|
||||
if (META_IS_WINDOW_ACTOR (child))
|
||||
{
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
|
||||
meta_window_actor_set_unobscured_region (window_actor, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -123,12 +138,11 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
paint_x_offset = paint_x_origin - actor_x_origin;
|
||||
paint_y_offset = paint_y_origin - actor_y_origin;
|
||||
|
||||
/* We walk the list from top to bottom (opposite of painting order),
|
||||
* and subtract the opaque area of each window out of the visible
|
||||
* region that we pass to the windows below.
|
||||
*/
|
||||
children = clutter_actor_get_children (actor);
|
||||
children = g_list_reverse (children);
|
||||
visible_rect.x = visible_rect.y = 0;
|
||||
visible_rect.width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
|
||||
visible_rect.height = clutter_actor_get_height (CLUTTER_ACTOR (stage));
|
||||
|
||||
unobscured_region = cairo_region_create_rectangle (&visible_rect);
|
||||
|
||||
/* Get the clipped redraw bounds from Clutter so that we can avoid
|
||||
* painting shadows on windows that don't need to be painted in this
|
||||
@@ -136,27 +150,38 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
* sizes, we could intersect this with an accurate union of the
|
||||
* monitors to avoid painting shadows that are visible only in the
|
||||
* holes. */
|
||||
stage = clutter_actor_get_stage (actor);
|
||||
clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
|
||||
&visible_rect);
|
||||
&clip_rect);
|
||||
|
||||
visible_region = cairo_region_create_rectangle (&visible_rect);
|
||||
clip_region = cairo_region_create_rectangle (&clip_rect);
|
||||
|
||||
if (info->unredirected_window != NULL)
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
cairo_rectangle_int_t unredirected_rect;
|
||||
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
|
||||
info = meta_screen_get_compositor_data (window_group->screen);
|
||||
if (info->unredirected_window != NULL)
|
||||
{
|
||||
cairo_rectangle_int_t unredirected_rect;
|
||||
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
|
||||
|
||||
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
|
||||
cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
|
||||
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
|
||||
cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
|
||||
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
|
||||
}
|
||||
}
|
||||
|
||||
for (l = children; l; l = l->next)
|
||||
/* We walk the list from top to bottom (opposite of painting order),
|
||||
* and subtract the opaque area of each window out of the visible
|
||||
* region that we pass to the windows below.
|
||||
*/
|
||||
clutter_actor_iter_init (&iter, actor);
|
||||
while (clutter_actor_iter_prev (&iter, &child))
|
||||
{
|
||||
if (!CLUTTER_ACTOR_IS_VISIBLE (l->data))
|
||||
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
|
||||
continue;
|
||||
|
||||
if (l->data == info->unredirected_window)
|
||||
if (!meta_is_wayland_compositor () &&
|
||||
info->unredirected_window != NULL &&
|
||||
child == CLUTTER_ACTOR (info->unredirected_window))
|
||||
continue;
|
||||
|
||||
/* If an actor has effects applied, then that can change the area
|
||||
@@ -175,12 +200,12 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
* as well for the same reason, but omitted for simplicity in the
|
||||
* hopes that no-one will do that.
|
||||
*/
|
||||
if (clutter_actor_has_effects (l->data))
|
||||
if (clutter_actor_has_effects (child))
|
||||
continue;
|
||||
|
||||
if (META_IS_WINDOW_ACTOR (l->data))
|
||||
if (META_IS_WINDOW_ACTOR (child))
|
||||
{
|
||||
MetaWindowActor *window_actor = l->data;
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
|
||||
int x, y;
|
||||
|
||||
if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
|
||||
@@ -189,65 +214,72 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
x += paint_x_offset;
|
||||
y += paint_y_offset;
|
||||
|
||||
/* Temporarily move to the coordinate system of the actor */
|
||||
cairo_region_translate (visible_region, - x, - y);
|
||||
|
||||
meta_window_actor_set_visible_region (window_actor, visible_region);
|
||||
/* Temporarily move to the coordinate system of the actor */
|
||||
cairo_region_translate (unobscured_region, - x, - y);
|
||||
cairo_region_translate (clip_region, - x, - y);
|
||||
|
||||
meta_window_actor_set_unobscured_region (window_actor, unobscured_region);
|
||||
meta_window_actor_set_clip_region (window_actor, clip_region);
|
||||
|
||||
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
|
||||
{
|
||||
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
|
||||
if (obscured_region)
|
||||
cairo_region_subtract (visible_region, obscured_region);
|
||||
{
|
||||
cairo_region_subtract (unobscured_region, obscured_region);
|
||||
cairo_region_subtract (clip_region, obscured_region);
|
||||
}
|
||||
}
|
||||
|
||||
meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
|
||||
cairo_region_translate (visible_region, x, y);
|
||||
meta_window_actor_set_clip_region_beneath (window_actor, clip_region);
|
||||
|
||||
cairo_region_translate (unobscured_region, x, y);
|
||||
cairo_region_translate (clip_region, x, y);
|
||||
}
|
||||
else if (META_IS_BACKGROUND_ACTOR (l->data) ||
|
||||
META_IS_BACKGROUND_GROUP (l->data))
|
||||
else if (META_IS_BACKGROUND_ACTOR (child) ||
|
||||
META_IS_BACKGROUND_GROUP (child))
|
||||
{
|
||||
ClutterActor *background_actor = l->data;
|
||||
int x, y;
|
||||
|
||||
if (!meta_actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y))
|
||||
if (!meta_actor_is_untransformed (child, &x, &y))
|
||||
continue;
|
||||
|
||||
x += paint_x_offset;
|
||||
y += paint_y_offset;
|
||||
|
||||
cairo_region_translate (visible_region, - x, - y);
|
||||
cairo_region_translate (clip_region, - x, - y);
|
||||
|
||||
if (META_IS_BACKGROUND_GROUP (background_actor))
|
||||
meta_background_group_set_visible_region (META_BACKGROUND_GROUP (background_actor), visible_region);
|
||||
if (META_IS_BACKGROUND_GROUP (child))
|
||||
meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), clip_region);
|
||||
else
|
||||
meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (background_actor), visible_region);
|
||||
cairo_region_translate (visible_region, x, y);
|
||||
meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (child), clip_region);
|
||||
cairo_region_translate (clip_region, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_region_destroy (visible_region);
|
||||
cairo_region_destroy (unobscured_region);
|
||||
cairo_region_destroy (clip_region);
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
|
||||
|
||||
/* Now that we are done painting, unset the visible regions (they will
|
||||
* mess up painting clones of our actors)
|
||||
*/
|
||||
for (l = children; l; l = l->next)
|
||||
clutter_actor_iter_init (&iter, actor);
|
||||
while (clutter_actor_iter_next (&iter, &child))
|
||||
{
|
||||
if (META_IS_WINDOW_ACTOR (l->data))
|
||||
if (META_IS_WINDOW_ACTOR (child))
|
||||
{
|
||||
MetaWindowActor *window_actor = l->data;
|
||||
meta_window_actor_reset_visible_regions (window_actor);
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
|
||||
meta_window_actor_reset_clip_regions (window_actor);
|
||||
}
|
||||
else if (META_IS_BACKGROUND_ACTOR (l->data))
|
||||
else if (META_IS_BACKGROUND_ACTOR (child))
|
||||
{
|
||||
MetaBackgroundActor *background_actor = l->data;
|
||||
meta_background_actor_set_visible_region (background_actor, NULL);
|
||||
MetaBackgroundActor *background_actor = META_BACKGROUND_ACTOR (child);
|
||||
meta_background_actor_set_clip_region (background_actor, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@@ -24,6 +24,8 @@
|
||||
#include <meta/meta-plugin.h>
|
||||
#include <meta/window.h>
|
||||
#include <meta/util.h>
|
||||
#include <meta/meta-background-group.h>
|
||||
#include <meta/meta-background-actor.h>
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(x) dgettext (GETTEXT_PACKAGE, x)
|
||||
@@ -98,6 +100,8 @@ static void kill_window_effects (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
static void kill_switch_workspace (MetaPlugin *plugin);
|
||||
|
||||
static void confirm_display_change (MetaPlugin *plugin);
|
||||
|
||||
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
|
||||
|
||||
META_PLUGIN_DECLARE(MetaDefaultPlugin, meta_default_plugin);
|
||||
@@ -113,6 +117,8 @@ struct _MetaDefaultPluginPrivate
|
||||
ClutterActor *desktop1;
|
||||
ClutterActor *desktop2;
|
||||
|
||||
ClutterActor *background_group;
|
||||
|
||||
MetaPluginInfo info;
|
||||
};
|
||||
|
||||
@@ -203,6 +209,7 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
|
||||
plugin_class->plugin_info = plugin_info;
|
||||
plugin_class->kill_window_effects = kill_window_effects;
|
||||
plugin_class->kill_switch_workspace = kill_switch_workspace;
|
||||
plugin_class->confirm_display_change = confirm_display_change;
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (MetaDefaultPluginPrivate));
|
||||
}
|
||||
@@ -299,9 +306,58 @@ show_stage (MetaPlugin *plugin)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_monitors_changed (MetaScreen *screen,
|
||||
MetaPlugin *plugin)
|
||||
{
|
||||
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
|
||||
int i, n;
|
||||
|
||||
clutter_actor_destroy_all_children (self->priv->background_group);
|
||||
|
||||
n = meta_screen_get_n_monitors (screen);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
MetaRectangle rect;
|
||||
ClutterActor *background;
|
||||
ClutterColor color;
|
||||
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
|
||||
background = meta_background_actor_new ();
|
||||
|
||||
clutter_actor_set_position (background, rect.x, rect.y);
|
||||
clutter_actor_set_size (background, rect.width, rect.height);
|
||||
|
||||
/* Don't use rand() here, mesa calls srand() internally when
|
||||
parsing the driconf XML, but it's nice if the colors are
|
||||
reproducible.
|
||||
*/
|
||||
clutter_color_init (&color,
|
||||
g_random_int () % 255,
|
||||
g_random_int () % 255,
|
||||
g_random_int () % 255,
|
||||
255);
|
||||
clutter_actor_set_background_color (background, &color);
|
||||
|
||||
clutter_actor_add_child (self->priv->background_group, background);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start (MetaPlugin *plugin)
|
||||
{
|
||||
MetaDefaultPlugin *self = META_DEFAULT_PLUGIN (plugin);
|
||||
MetaScreen *screen = meta_plugin_get_screen (plugin);
|
||||
|
||||
self->priv->background_group = meta_background_group_new ();
|
||||
clutter_actor_insert_child_below (meta_get_window_group_for_screen (screen),
|
||||
self->priv->background_group, NULL);
|
||||
|
||||
g_signal_connect (screen, "monitors-changed",
|
||||
G_CALLBACK (on_monitors_changed), plugin);
|
||||
on_monitors_changed (screen, plugin);
|
||||
|
||||
meta_later_add (META_LATER_BEFORE_REDRAW,
|
||||
(GSourceFunc) show_stage,
|
||||
plugin,
|
||||
@@ -782,3 +838,33 @@ plugin_info (MetaPlugin *plugin)
|
||||
|
||||
return &priv->info;
|
||||
}
|
||||
|
||||
static void
|
||||
on_dialog_closed (GPid pid,
|
||||
gint status,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaPlugin *plugin = user_data;
|
||||
gboolean ok;
|
||||
|
||||
ok = g_spawn_check_exit_status (status, NULL);
|
||||
meta_plugin_complete_display_change (plugin, ok);
|
||||
}
|
||||
|
||||
static void
|
||||
confirm_display_change (MetaPlugin *plugin)
|
||||
{
|
||||
GPid pid;
|
||||
|
||||
pid = meta_show_dialog ("--question",
|
||||
"Does the display look OK?",
|
||||
"20",
|
||||
NULL,
|
||||
"_Keep This Configuration",
|
||||
"_Restore Previous Configuration",
|
||||
"preferences-desktop-display",
|
||||
0,
|
||||
NULL, NULL);
|
||||
|
||||
g_child_watch_add (pid, on_dialog_closed, plugin);
|
||||
}
|
||||
|
@@ -35,7 +35,8 @@ typedef enum
|
||||
META_DO_GRAVITY_ADJUST = 1 << 1,
|
||||
META_IS_USER_ACTION = 1 << 2,
|
||||
META_IS_MOVE_ACTION = 1 << 3,
|
||||
META_IS_RESIZE_ACTION = 1 << 4
|
||||
META_IS_RESIZE_ACTION = 1 << 4,
|
||||
META_IS_WAYLAND_RESIZE = 1 << 5
|
||||
} MetaMoveResizeFlags;
|
||||
|
||||
void meta_window_constrain (MetaWindow *window,
|
||||
|
@@ -269,6 +269,8 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
|
||||
MetaDisplay *display;
|
||||
MetaScreen *screen;
|
||||
MetaWindow *grab_window;
|
||||
MetaStackWindow stack_window;
|
||||
MetaStackWindow stack_sibling;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_xwindow (display, xwindow);
|
||||
@@ -281,9 +283,13 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
|
||||
changes.sibling = grab_window->frame ? grab_window->frame->xwindow
|
||||
: grab_window->xwindow;
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = xwindow;
|
||||
stack_sibling.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_sibling.x11.xwindow = changes.sibling;
|
||||
meta_stack_tracker_record_lower_below (screen->stack_tracker,
|
||||
xwindow,
|
||||
changes.sibling,
|
||||
&stack_window,
|
||||
&stack_sibling,
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
|
||||
meta_error_trap_push (display);
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "keybindings-private.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/barrier.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
#include <libsn/sn.h>
|
||||
@@ -86,6 +87,14 @@ typedef enum {
|
||||
META_TILE_MAXIMIZED
|
||||
} MetaTileMode;
|
||||
|
||||
typedef enum {
|
||||
META_FOCUS_NONE = 0,
|
||||
META_FOCUS_X_CLIENT = 1,
|
||||
META_FOCUS_WAYLAND_CLIENT = 2,
|
||||
META_FOCUS_NO_FOCUS_WINDOW = 3,
|
||||
META_FOCUS_STAGE = 4
|
||||
} MetaFocusType;
|
||||
|
||||
struct _MetaDisplay
|
||||
{
|
||||
GObject parent_instance;
|
||||
@@ -103,19 +112,21 @@ struct _MetaDisplay
|
||||
#include <meta/atomnames.h>
|
||||
#undef item
|
||||
|
||||
/* This is the actual window from focus events,
|
||||
* not the one we last set
|
||||
/* The window and serial of the most recent FocusIn event. */
|
||||
Window server_focus_window;
|
||||
gulong server_focus_serial;
|
||||
|
||||
/* Our best guess as to the "currently" focused window (that is, the
|
||||
* window that we expect will be focused at the point when the X
|
||||
* server processes our next request), and the serial of the request
|
||||
* or event that caused this.
|
||||
*/
|
||||
MetaWindow *focus_window;
|
||||
|
||||
/* window we are expecting a FocusIn event for or the current focus
|
||||
* window if we are not expecting any FocusIn/FocusOut events; not
|
||||
* perfect because applications can call XSetInputFocus directly.
|
||||
* (It could also be messed up if a timestamp later than current
|
||||
* time is sent to meta_display_set_input_focus_window, though that
|
||||
* would be a programming error). See bug 154598 for more info.
|
||||
*/
|
||||
MetaWindow *expected_focus_window;
|
||||
/* For windows we've focused that don't necessarily have an X window,
|
||||
* like the no_focus_window or the stage X window. */
|
||||
Window focus_xwindow;
|
||||
gulong focus_serial;
|
||||
MetaFocusType focus_type;
|
||||
|
||||
/* last timestamp passed to XSetInputFocus */
|
||||
guint32 last_focus_time;
|
||||
@@ -178,7 +189,7 @@ struct _MetaDisplay
|
||||
MetaWindow* autoraise_window;
|
||||
|
||||
/* Alt+click button grabs */
|
||||
unsigned int window_grab_modifiers;
|
||||
ClutterModifierType window_grab_modifiers;
|
||||
|
||||
/* current window operation */
|
||||
MetaGrabOp grab_op;
|
||||
@@ -239,6 +250,8 @@ struct _MetaDisplay
|
||||
unsigned int meta_mask;
|
||||
MetaKeyCombo overlay_key_combo;
|
||||
gboolean overlay_key_only_pressed;
|
||||
MetaKeyCombo *iso_next_group_combos;
|
||||
int n_iso_next_group_combos;
|
||||
|
||||
/* Monitor cache */
|
||||
unsigned int monitor_cache_invalidated : 1;
|
||||
@@ -457,14 +470,28 @@ void meta_display_remove_autoraise_callback (MetaDisplay *display);
|
||||
void meta_display_overlay_key_activate (MetaDisplay *display);
|
||||
void meta_display_accelerator_activate (MetaDisplay *display,
|
||||
guint action,
|
||||
guint deviceid);
|
||||
guint deviceid,
|
||||
guint timestamp);
|
||||
gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
|
||||
|
||||
/* In above-tab-keycode.c */
|
||||
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
||||
|
||||
gboolean meta_display_handle_xevent (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
|
||||
gboolean meta_display_handle_event (MetaDisplay *display,
|
||||
const ClutterEvent *event);
|
||||
|
||||
#ifdef HAVE_XI23
|
||||
gboolean meta_display_process_barrier_event (MetaDisplay *display,
|
||||
XIBarrierEvent *event);
|
||||
#endif /* HAVE_XI23 */
|
||||
|
||||
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaFocusType type,
|
||||
Window window,
|
||||
guint32 timestamp);
|
||||
|
||||
#endif
|
||||
|
1258
src/core/display.c
1258
src/core/display.c
File diff suppressed because it is too large
Load Diff
539
src/core/edid-parse.c
Normal file
539
src/core/edid-parse.c
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright 2007 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
||||
* license, and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Author: Soren Sandmann <sandmann@redhat.com> */
|
||||
|
||||
#include "edid.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
|
||||
static int
|
||||
get_bit (int in, int bit)
|
||||
{
|
||||
return (in & (1 << bit)) >> bit;
|
||||
}
|
||||
|
||||
static int
|
||||
get_bits (int in, int begin, int end)
|
||||
{
|
||||
int mask = (1 << (end - begin + 1)) - 1;
|
||||
|
||||
return (in >> begin) & mask;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_header (const uchar *edid)
|
||||
{
|
||||
if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
int is_model_year;
|
||||
|
||||
/* Manufacturer Code */
|
||||
info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
|
||||
info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
|
||||
info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
|
||||
info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
|
||||
info->manufacturer_code[3] = '\0';
|
||||
|
||||
info->manufacturer_code[0] += 'A' - 1;
|
||||
info->manufacturer_code[1] += 'A' - 1;
|
||||
info->manufacturer_code[2] += 'A' - 1;
|
||||
|
||||
/* Product Code */
|
||||
info->product_code = edid[0x0b] << 8 | edid[0x0a];
|
||||
|
||||
/* Serial Number */
|
||||
info->serial_number =
|
||||
edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
|
||||
|
||||
/* Week and Year */
|
||||
is_model_year = FALSE;
|
||||
switch (edid[0x10])
|
||||
{
|
||||
case 0x00:
|
||||
info->production_week = -1;
|
||||
break;
|
||||
|
||||
case 0xff:
|
||||
info->production_week = -1;
|
||||
is_model_year = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
info->production_week = edid[0x10];
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_model_year)
|
||||
{
|
||||
info->production_year = -1;
|
||||
info->model_year = 1990 + edid[0x11];
|
||||
}
|
||||
else
|
||||
{
|
||||
info->production_year = 1990 + edid[0x11];
|
||||
info->model_year = -1;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_edid_version (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
info->major_version = edid[0x12];
|
||||
info->minor_version = edid[0x13];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_display_parameters (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
/* Digital vs Analog */
|
||||
info->is_digital = get_bit (edid[0x14], 7);
|
||||
|
||||
if (info->is_digital)
|
||||
{
|
||||
int bits;
|
||||
|
||||
static const int bit_depth[8] =
|
||||
{
|
||||
-1, 6, 8, 10, 12, 14, 16, -1
|
||||
};
|
||||
|
||||
static const Interface interfaces[6] =
|
||||
{
|
||||
UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
|
||||
};
|
||||
|
||||
bits = get_bits (edid[0x14], 4, 6);
|
||||
info->connector.digital.bits_per_primary = bit_depth[bits];
|
||||
|
||||
bits = get_bits (edid[0x14], 0, 3);
|
||||
|
||||
if (bits <= 5)
|
||||
info->connector.digital.interface = interfaces[bits];
|
||||
else
|
||||
info->connector.digital.interface = UNDEFINED;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bits = get_bits (edid[0x14], 5, 6);
|
||||
|
||||
static const double levels[][3] =
|
||||
{
|
||||
{ 0.7, 0.3, 1.0 },
|
||||
{ 0.714, 0.286, 1.0 },
|
||||
{ 1.0, 0.4, 1.4 },
|
||||
{ 0.7, 0.0, 0.7 },
|
||||
};
|
||||
|
||||
info->connector.analog.video_signal_level = levels[bits][0];
|
||||
info->connector.analog.sync_signal_level = levels[bits][1];
|
||||
info->connector.analog.total_signal_level = levels[bits][2];
|
||||
|
||||
info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
|
||||
|
||||
info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
|
||||
info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
|
||||
info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
|
||||
|
||||
info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
|
||||
}
|
||||
|
||||
/* Screen Size / Aspect Ratio */
|
||||
if (edid[0x15] == 0 && edid[0x16] == 0)
|
||||
{
|
||||
info->width_mm = -1;
|
||||
info->height_mm = -1;
|
||||
info->aspect_ratio = -1.0;
|
||||
}
|
||||
else if (edid[0x16] == 0)
|
||||
{
|
||||
info->width_mm = -1;
|
||||
info->height_mm = -1;
|
||||
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
|
||||
}
|
||||
else if (edid[0x15] == 0)
|
||||
{
|
||||
info->width_mm = -1;
|
||||
info->height_mm = -1;
|
||||
info->aspect_ratio = 100.0 / (edid[0x16] + 99);
|
||||
info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
|
||||
}
|
||||
else
|
||||
{
|
||||
info->width_mm = 10 * edid[0x15];
|
||||
info->height_mm = 10 * edid[0x16];
|
||||
}
|
||||
|
||||
/* Gamma */
|
||||
if (edid[0x17] == 0xFF)
|
||||
info->gamma = -1.0;
|
||||
else
|
||||
info->gamma = (edid[0x17] + 100.0) / 100.0;
|
||||
|
||||
/* Features */
|
||||
info->standby = get_bit (edid[0x18], 7);
|
||||
info->suspend = get_bit (edid[0x18], 6);
|
||||
info->active_off = get_bit (edid[0x18], 5);
|
||||
|
||||
if (info->is_digital)
|
||||
{
|
||||
info->connector.digital.rgb444 = TRUE;
|
||||
if (get_bit (edid[0x18], 3))
|
||||
info->connector.digital.ycrcb444 = 1;
|
||||
if (get_bit (edid[0x18], 4))
|
||||
info->connector.digital.ycrcb422 = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bits = get_bits (edid[0x18], 3, 4);
|
||||
ColorType color_type[4] =
|
||||
{
|
||||
MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
|
||||
};
|
||||
|
||||
info->connector.analog.color_type = color_type[bits];
|
||||
}
|
||||
|
||||
info->srgb_is_standard = get_bit (edid[0x18], 2);
|
||||
|
||||
/* In 1.3 this is called "has preferred timing" */
|
||||
info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
|
||||
|
||||
/* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
|
||||
info->continuous_frequency = get_bit (edid[0x18], 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static double
|
||||
decode_fraction (int high, int low)
|
||||
{
|
||||
double result = 0.0;
|
||||
int i;
|
||||
|
||||
high = (high << 2) | low;
|
||||
|
||||
for (i = 0; i < 10; ++i)
|
||||
result += get_bit (high, i) * pow (2, i - 10);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_color_characteristics (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
|
||||
info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
|
||||
info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
|
||||
info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
|
||||
info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
|
||||
info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
|
||||
info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
|
||||
info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_established_timings (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
static const Timing established[][8] =
|
||||
{
|
||||
{
|
||||
{ 800, 600, 60 },
|
||||
{ 800, 600, 56 },
|
||||
{ 640, 480, 75 },
|
||||
{ 640, 480, 72 },
|
||||
{ 640, 480, 67 },
|
||||
{ 640, 480, 60 },
|
||||
{ 720, 400, 88 },
|
||||
{ 720, 400, 70 }
|
||||
},
|
||||
{
|
||||
{ 1280, 1024, 75 },
|
||||
{ 1024, 768, 75 },
|
||||
{ 1024, 768, 70 },
|
||||
{ 1024, 768, 60 },
|
||||
{ 1024, 768, 87 },
|
||||
{ 832, 624, 75 },
|
||||
{ 800, 600, 75 },
|
||||
{ 800, 600, 72 }
|
||||
},
|
||||
{
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 0 },
|
||||
{ 1152, 870, 75 }
|
||||
},
|
||||
};
|
||||
|
||||
int i, j, idx;
|
||||
|
||||
idx = 0;
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
for (j = 0; j < 8; ++j)
|
||||
{
|
||||
int byte = edid[0x23 + i];
|
||||
|
||||
if (get_bit (byte, j) && established[i][j].frequency != 0)
|
||||
info->established[idx++] = established[i][j];
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
decode_standard_timings (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
int first = edid[0x26 + 2 * i];
|
||||
int second = edid[0x27 + 2 * i];
|
||||
|
||||
if (first != 0x01 && second != 0x01)
|
||||
{
|
||||
int w = 8 * (first + 31);
|
||||
int h = 0;
|
||||
|
||||
switch (get_bits (second, 6, 7))
|
||||
{
|
||||
case 0x00: h = (w / 16) * 10; break;
|
||||
case 0x01: h = (w / 4) * 3; break;
|
||||
case 0x02: h = (w / 5) * 4; break;
|
||||
case 0x03: h = (w / 16) * 9; break;
|
||||
}
|
||||
|
||||
info->standard[i].width = w;
|
||||
info->standard[i].height = h;
|
||||
info->standard[i].frequency = get_bits (second, 0, 5) + 60;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
decode_lf_string (const uchar *s, int n_chars, char *result)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_chars; ++i)
|
||||
{
|
||||
if (s[i] == 0x0a)
|
||||
{
|
||||
*result++ = '\0';
|
||||
break;
|
||||
}
|
||||
else if (s[i] == 0x00)
|
||||
{
|
||||
/* Convert embedded 0's to spaces */
|
||||
*result++ = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
*result++ = s[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
decode_display_descriptor (const uchar *desc,
|
||||
MonitorInfo *info)
|
||||
{
|
||||
switch (desc[0x03])
|
||||
{
|
||||
case 0xFC:
|
||||
decode_lf_string (desc + 5, 13, info->dsc_product_name);
|
||||
break;
|
||||
case 0xFF:
|
||||
decode_lf_string (desc + 5, 13, info->dsc_serial_number);
|
||||
break;
|
||||
case 0xFE:
|
||||
decode_lf_string (desc + 5, 13, info->dsc_string);
|
||||
break;
|
||||
case 0xFD:
|
||||
/* Range Limits */
|
||||
break;
|
||||
case 0xFB:
|
||||
/* Color Point */
|
||||
break;
|
||||
case 0xFA:
|
||||
/* Timing Identifications */
|
||||
break;
|
||||
case 0xF9:
|
||||
/* Color Management */
|
||||
break;
|
||||
case 0xF8:
|
||||
/* Timing Codes */
|
||||
break;
|
||||
case 0xF7:
|
||||
/* Established Timings */
|
||||
break;
|
||||
case 0x10:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
decode_detailed_timing (const uchar *timing,
|
||||
DetailedTiming *detailed)
|
||||
{
|
||||
int bits;
|
||||
StereoType stereo[] =
|
||||
{
|
||||
NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
|
||||
TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
|
||||
FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
|
||||
};
|
||||
|
||||
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
|
||||
detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
|
||||
detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
|
||||
detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
|
||||
detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
|
||||
detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
|
||||
detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
|
||||
detailed->v_front_porch =
|
||||
get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
|
||||
detailed->v_sync =
|
||||
get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
|
||||
detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
|
||||
detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
|
||||
detailed->right_border = timing[0x0f];
|
||||
detailed->top_border = timing[0x10];
|
||||
|
||||
detailed->interlaced = get_bit (timing[0x11], 7);
|
||||
|
||||
/* Stereo */
|
||||
bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
|
||||
detailed->stereo = stereo[bits];
|
||||
|
||||
/* Sync */
|
||||
bits = timing[0x11];
|
||||
|
||||
detailed->digital_sync = get_bit (bits, 4);
|
||||
if (detailed->digital_sync)
|
||||
{
|
||||
detailed->connector.digital.composite = !get_bit (bits, 3);
|
||||
|
||||
if (detailed->connector.digital.composite)
|
||||
{
|
||||
detailed->connector.digital.serrations = get_bit (bits, 2);
|
||||
detailed->connector.digital.negative_vsync = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
detailed->connector.digital.serrations = FALSE;
|
||||
detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
|
||||
}
|
||||
|
||||
detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
detailed->connector.analog.bipolar = get_bit (bits, 3);
|
||||
detailed->connector.analog.serrations = get_bit (bits, 2);
|
||||
detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
decode_descriptors (const uchar *edid, MonitorInfo *info)
|
||||
{
|
||||
int i;
|
||||
int timing_idx;
|
||||
|
||||
timing_idx = 0;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
int index = 0x36 + i * 18;
|
||||
|
||||
if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
|
||||
{
|
||||
decode_display_descriptor (edid + index, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
decode_detailed_timing (edid + index, &(info->detailed_timings[timing_idx++]));
|
||||
}
|
||||
}
|
||||
|
||||
info->n_detailed_timings = timing_idx;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
decode_check_sum (const uchar *edid,
|
||||
MonitorInfo *info)
|
||||
{
|
||||
int i;
|
||||
uchar check = 0;
|
||||
|
||||
for (i = 0; i < 128; ++i)
|
||||
check += edid[i];
|
||||
|
||||
info->checksum = check;
|
||||
}
|
||||
|
||||
MonitorInfo *
|
||||
decode_edid (const uchar *edid)
|
||||
{
|
||||
MonitorInfo *info = g_new0 (MonitorInfo, 1);
|
||||
|
||||
decode_check_sum (edid, info);
|
||||
|
||||
if (decode_header (edid)
|
||||
&& decode_vendor_and_product_identification (edid, info)
|
||||
&& decode_edid_version (edid, info)
|
||||
&& decode_display_parameters (edid, info)
|
||||
&& decode_color_characteristics (edid, info)
|
||||
&& decode_established_timings (edid, info)
|
||||
&& decode_standard_timings (edid, info)
|
||||
&& decode_descriptors (edid, info))
|
||||
{
|
||||
return info;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (info);
|
||||
return NULL;
|
||||
}
|
||||
}
|
195
src/core/edid.h
Normal file
195
src/core/edid.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/* edid.h
|
||||
*
|
||||
* Copyright 2007, 2008, Red Hat, Inc.
|
||||
*
|
||||
* This file is part of the Gnome Library.
|
||||
*
|
||||
* The Gnome Library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The Gnome Library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with the Gnome Library; see the file COPYING.LIB. If not,
|
||||
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Author: Soren Sandmann <sandmann@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef EDID_H
|
||||
#define EDID_H
|
||||
|
||||
typedef unsigned char uchar;
|
||||
typedef struct MonitorInfo MonitorInfo;
|
||||
typedef struct Timing Timing;
|
||||
typedef struct DetailedTiming DetailedTiming;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNDEFINED,
|
||||
DVI,
|
||||
HDMI_A,
|
||||
HDMI_B,
|
||||
MDDI,
|
||||
DISPLAY_PORT
|
||||
} Interface;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNDEFINED_COLOR,
|
||||
MONOCHROME,
|
||||
RGB,
|
||||
OTHER_COLOR
|
||||
} ColorType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NO_STEREO,
|
||||
FIELD_RIGHT,
|
||||
FIELD_LEFT,
|
||||
TWO_WAY_RIGHT_ON_EVEN,
|
||||
TWO_WAY_LEFT_ON_EVEN,
|
||||
FOUR_WAY_INTERLEAVED,
|
||||
SIDE_BY_SIDE
|
||||
} StereoType;
|
||||
|
||||
struct Timing
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int frequency;
|
||||
};
|
||||
|
||||
struct DetailedTiming
|
||||
{
|
||||
int pixel_clock;
|
||||
int h_addr;
|
||||
int h_blank;
|
||||
int h_sync;
|
||||
int h_front_porch;
|
||||
int v_addr;
|
||||
int v_blank;
|
||||
int v_sync;
|
||||
int v_front_porch;
|
||||
int width_mm;
|
||||
int height_mm;
|
||||
int right_border;
|
||||
int top_border;
|
||||
int interlaced;
|
||||
StereoType stereo;
|
||||
|
||||
int digital_sync;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int bipolar;
|
||||
int serrations;
|
||||
int sync_on_green;
|
||||
} analog;
|
||||
|
||||
struct
|
||||
{
|
||||
int composite;
|
||||
int serrations;
|
||||
int negative_vsync;
|
||||
int negative_hsync;
|
||||
} digital;
|
||||
} connector;
|
||||
};
|
||||
|
||||
struct MonitorInfo
|
||||
{
|
||||
int checksum;
|
||||
char manufacturer_code[4];
|
||||
int product_code;
|
||||
unsigned int serial_number;
|
||||
|
||||
int production_week; /* -1 if not specified */
|
||||
int production_year; /* -1 if not specified */
|
||||
int model_year; /* -1 if not specified */
|
||||
|
||||
int major_version;
|
||||
int minor_version;
|
||||
|
||||
int is_digital;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int bits_per_primary;
|
||||
Interface interface;
|
||||
int rgb444;
|
||||
int ycrcb444;
|
||||
int ycrcb422;
|
||||
} digital;
|
||||
|
||||
struct
|
||||
{
|
||||
double video_signal_level;
|
||||
double sync_signal_level;
|
||||
double total_signal_level;
|
||||
|
||||
int blank_to_black;
|
||||
|
||||
int separate_hv_sync;
|
||||
int composite_sync_on_h;
|
||||
int composite_sync_on_green;
|
||||
int serration_on_vsync;
|
||||
ColorType color_type;
|
||||
} analog;
|
||||
} connector;
|
||||
|
||||
int width_mm; /* -1 if not specified */
|
||||
int height_mm; /* -1 if not specified */
|
||||
double aspect_ratio; /* -1.0 if not specififed */
|
||||
|
||||
double gamma; /* -1.0 if not specified */
|
||||
|
||||
int standby;
|
||||
int suspend;
|
||||
int active_off;
|
||||
|
||||
int srgb_is_standard;
|
||||
int preferred_timing_includes_native;
|
||||
int continuous_frequency;
|
||||
|
||||
double red_x;
|
||||
double red_y;
|
||||
double green_x;
|
||||
double green_y;
|
||||
double blue_x;
|
||||
double blue_y;
|
||||
double white_x;
|
||||
double white_y;
|
||||
|
||||
Timing established[24]; /* Terminated by 0x0x0 */
|
||||
Timing standard[8];
|
||||
|
||||
int n_detailed_timings;
|
||||
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
|
||||
* mode, it is the first one
|
||||
* (whether it has, is
|
||||
* determined by the
|
||||
* preferred_timing_includes
|
||||
* bit.
|
||||
*/
|
||||
|
||||
/* Optional product description */
|
||||
char dsc_serial_number[14];
|
||||
char dsc_product_name[14];
|
||||
char dsc_string[14]; /* Unspecified ASCII data */
|
||||
};
|
||||
|
||||
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
|
@@ -47,6 +47,7 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
XSetWindowAttributes attrs;
|
||||
Visual *visual;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame)
|
||||
return;
|
||||
@@ -105,8 +106,10 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
frame->rect.height,
|
||||
frame->window->screen->number,
|
||||
&create_serial);
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = frame->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
frame->xwindow,
|
||||
&stack_window,
|
||||
create_serial);
|
||||
|
||||
meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
|
||||
@@ -138,8 +141,9 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
window->rect.x = 0;
|
||||
window->rect.y = 0;
|
||||
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_remove (window->screen->stack_tracker,
|
||||
window->xwindow,
|
||||
&stack_window,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
@@ -174,6 +178,7 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
{
|
||||
MetaFrame *frame;
|
||||
MetaFrameBorders borders;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame == NULL)
|
||||
return;
|
||||
@@ -200,8 +205,10 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
|
||||
window->unmaps_pending += 1;
|
||||
}
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
window->xwindow,
|
||||
&stack_window,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
|
@@ -69,7 +69,6 @@ void meta_window_ungrab_all_keys (MetaWindow *window,
|
||||
gboolean meta_display_process_key_event (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
XIDeviceEvent *event);
|
||||
void meta_set_keybindings_disabled (gboolean setting);
|
||||
void meta_display_process_mapping_event (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
|
||||
|
@@ -53,10 +53,13 @@
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "meta-wayland-private.h"
|
||||
#endif
|
||||
|
||||
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
|
||||
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
|
||||
|
||||
static gboolean all_bindings_disabled = FALSE;
|
||||
#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings"
|
||||
|
||||
static gboolean add_builtin_keybinding (MetaDisplay *display,
|
||||
const char *name,
|
||||
@@ -302,6 +305,172 @@ reload_modmap (MetaDisplay *display)
|
||||
display->meta_mask);
|
||||
}
|
||||
|
||||
/* Original code from gdk_x11_keymap_get_entries_for_keyval() in
|
||||
* gdkkeys-x11.c */
|
||||
static int
|
||||
get_keycodes_for_keysym (MetaDisplay *display,
|
||||
int keysym,
|
||||
int **keycodes)
|
||||
{
|
||||
GArray *retval;
|
||||
int n_keycodes;
|
||||
int keycode;
|
||||
|
||||
retval = g_array_new (FALSE, FALSE, sizeof (int));
|
||||
|
||||
keycode = display->min_keycode;
|
||||
while (keycode <= display->max_keycode)
|
||||
{
|
||||
const KeySym *syms = display->keymap + (keycode - display->min_keycode) * display->keysyms_per_keycode;
|
||||
int i = 0;
|
||||
|
||||
while (i < display->keysyms_per_keycode)
|
||||
{
|
||||
if (syms[i] == (unsigned int)keysym)
|
||||
g_array_append_val (retval, keycode);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
++keycode;
|
||||
}
|
||||
|
||||
n_keycodes = retval->len;
|
||||
*keycodes = (int*) g_array_free (retval, n_keycodes == 0 ? TRUE : FALSE);
|
||||
|
||||
return n_keycodes;
|
||||
}
|
||||
|
||||
static void
|
||||
reload_iso_next_group_combos (MetaDisplay *display)
|
||||
{
|
||||
const char *iso_next_group_option;
|
||||
MetaKeyCombo *combos;
|
||||
int *keycodes;
|
||||
int n_keycodes;
|
||||
int n_combos;
|
||||
int i;
|
||||
|
||||
g_clear_pointer (&display->iso_next_group_combos, g_free);
|
||||
display->n_iso_next_group_combos = 0;
|
||||
|
||||
iso_next_group_option = meta_prefs_get_iso_next_group_option ();
|
||||
if (iso_next_group_option == NULL)
|
||||
return;
|
||||
|
||||
n_keycodes = get_keycodes_for_keysym (display, XK_ISO_Next_Group, &keycodes);
|
||||
|
||||
if (g_str_equal (iso_next_group_option, "toggle") ||
|
||||
g_str_equal (iso_next_group_option, "lalt_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "lwin_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "rwin_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "lshift_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "rshift_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "lctrl_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "rctrl_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "sclk_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "menu_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "caps_toggle"))
|
||||
{
|
||||
n_combos = n_keycodes;
|
||||
combos = g_new (MetaKeyCombo, n_combos);
|
||||
|
||||
for (i = 0; i < n_keycodes; ++i)
|
||||
{
|
||||
combos[i].keysym = XK_ISO_Next_Group;
|
||||
combos[i].keycode = keycodes[i];
|
||||
combos[i].modifiers = 0;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (iso_next_group_option, "shift_caps_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "shifts_toggle"))
|
||||
{
|
||||
n_combos = n_keycodes;
|
||||
combos = g_new (MetaKeyCombo, n_combos);
|
||||
|
||||
for (i = 0; i < n_keycodes; ++i)
|
||||
{
|
||||
combos[i].keysym = XK_ISO_Next_Group;
|
||||
combos[i].keycode = keycodes[i];
|
||||
combos[i].modifiers = ShiftMask;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (iso_next_group_option, "alt_caps_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "alt_space_toggle"))
|
||||
{
|
||||
n_combos = n_keycodes;
|
||||
combos = g_new (MetaKeyCombo, n_combos);
|
||||
|
||||
for (i = 0; i < n_keycodes; ++i)
|
||||
{
|
||||
combos[i].keysym = XK_ISO_Next_Group;
|
||||
combos[i].keycode = keycodes[i];
|
||||
combos[i].modifiers = Mod1Mask;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (iso_next_group_option, "ctrl_shift_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "lctrl_lshift_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "rctrl_rshift_toggle"))
|
||||
{
|
||||
n_combos = n_keycodes * 2;
|
||||
combos = g_new (MetaKeyCombo, n_combos);
|
||||
|
||||
for (i = 0; i < n_keycodes; ++i)
|
||||
{
|
||||
combos[i].keysym = XK_ISO_Next_Group;
|
||||
combos[i].keycode = keycodes[i];
|
||||
combos[i].modifiers = ShiftMask;
|
||||
|
||||
combos[i + n_keycodes].keysym = XK_ISO_Next_Group;
|
||||
combos[i + n_keycodes].keycode = keycodes[i];
|
||||
combos[i + n_keycodes].modifiers = ControlMask;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (iso_next_group_option, "ctrl_alt_toggle"))
|
||||
{
|
||||
n_combos = n_keycodes * 2;
|
||||
combos = g_new (MetaKeyCombo, n_combos);
|
||||
|
||||
for (i = 0; i < n_keycodes; ++i)
|
||||
{
|
||||
combos[i].keysym = XK_ISO_Next_Group;
|
||||
combos[i].keycode = keycodes[i];
|
||||
combos[i].modifiers = Mod1Mask;
|
||||
|
||||
combos[i + n_keycodes].keysym = XK_ISO_Next_Group;
|
||||
combos[i + n_keycodes].keycode = keycodes[i];
|
||||
combos[i + n_keycodes].modifiers = ControlMask;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (iso_next_group_option, "alt_shift_toggle") ||
|
||||
g_str_equal (iso_next_group_option, "lalt_lshift_toggle"))
|
||||
{
|
||||
n_combos = n_keycodes * 2;
|
||||
combos = g_new (MetaKeyCombo, n_combos);
|
||||
|
||||
for (i = 0; i < n_keycodes; ++i)
|
||||
{
|
||||
combos[i].keysym = XK_ISO_Next_Group;
|
||||
combos[i].keycode = keycodes[i];
|
||||
combos[i].modifiers = Mod1Mask;
|
||||
|
||||
combos[i + n_keycodes].keysym = XK_ISO_Next_Group;
|
||||
combos[i + n_keycodes].keycode = keycodes[i];
|
||||
combos[i + n_keycodes].modifiers = ShiftMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
n_combos = 0;
|
||||
combos = NULL;
|
||||
}
|
||||
|
||||
g_free (keycodes);
|
||||
|
||||
display->n_iso_next_group_combos = n_combos;
|
||||
display->iso_next_group_combos = combos;
|
||||
}
|
||||
|
||||
static guint
|
||||
keysym_to_keycode (MetaDisplay *display,
|
||||
guint keysym)
|
||||
@@ -328,6 +497,8 @@ reload_keycodes (MetaDisplay *display)
|
||||
display->overlay_key_combo.keycode = 0;
|
||||
}
|
||||
|
||||
reload_iso_next_group_combos (display);
|
||||
|
||||
if (display->key_bindings)
|
||||
{
|
||||
int i;
|
||||
@@ -1026,6 +1197,22 @@ meta_screen_change_keygrabs (MetaScreen *screen,
|
||||
display->overlay_key_combo.keycode,
|
||||
display->overlay_key_combo.modifiers);
|
||||
|
||||
if (display->iso_next_group_combos)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < display->n_iso_next_group_combos)
|
||||
{
|
||||
if (display->iso_next_group_combos[i].keycode != 0)
|
||||
{
|
||||
meta_change_keygrab (display, screen->xroot, grab,
|
||||
display->iso_next_group_combos[i].keysym,
|
||||
display->iso_next_group_combos[i].keycode,
|
||||
display->iso_next_group_combos[i].modifiers);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
change_binding_keygrabs (screen->display->key_bindings,
|
||||
screen->display->n_key_bindings,
|
||||
screen->display, screen->xroot,
|
||||
@@ -1128,7 +1315,7 @@ handle_external_grab (MetaDisplay *display,
|
||||
guint action = meta_display_get_keybinding_action (display,
|
||||
binding->keycode,
|
||||
binding->mask);
|
||||
meta_display_accelerator_activate (display, action, event->deviceid);
|
||||
meta_display_accelerator_activate (display, action, event->deviceid, event->time);
|
||||
}
|
||||
|
||||
|
||||
@@ -1264,7 +1451,8 @@ grab_status_to_string (int status)
|
||||
static gboolean
|
||||
grab_keyboard (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
guint32 timestamp)
|
||||
guint32 timestamp,
|
||||
int grab_mode)
|
||||
{
|
||||
int result;
|
||||
int grab_status;
|
||||
@@ -1280,13 +1468,22 @@ grab_keyboard (MetaDisplay *display,
|
||||
*/
|
||||
meta_error_trap_push_with_return (display);
|
||||
|
||||
/* Strictly, we only need to set grab_mode on the keyboard device
|
||||
* while the pointer should always be XIGrabModeAsync. Unfortunately
|
||||
* there is a bug in the X server, only fixed (link below) in 1.15,
|
||||
* which swaps these arguments for keyboard devices. As such, we set
|
||||
* both the device and the paired device mode which works around
|
||||
* that bug and also works on fixed X servers.
|
||||
*
|
||||
* http://cgit.freedesktop.org/xorg/xserver/commit/?id=9003399708936481083424b4ff8f18a16b88b7b3
|
||||
*/
|
||||
grab_status = XIGrabDevice (display->xdisplay,
|
||||
META_VIRTUAL_CORE_KEYBOARD_ID,
|
||||
xwindow,
|
||||
timestamp,
|
||||
None,
|
||||
XIGrabModeAsync, XIGrabModeAsync,
|
||||
True, /* owner_events */
|
||||
grab_mode, grab_mode,
|
||||
False, /* owner_events */
|
||||
&mask);
|
||||
|
||||
if (grab_status != Success)
|
||||
@@ -1339,7 +1536,7 @@ meta_screen_grab_all_keys (MetaScreen *screen, guint32 timestamp)
|
||||
|
||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||
"Grabbing all keys on RootWindow\n");
|
||||
retval = grab_keyboard (screen->display, screen->xroot, timestamp);
|
||||
retval = grab_keyboard (screen->display, screen->xroot, timestamp, XIGrabModeAsync);
|
||||
if (retval)
|
||||
{
|
||||
screen->all_keys_grabbed = TRUE;
|
||||
@@ -1392,7 +1589,7 @@ meta_window_grab_all_keys (MetaWindow *window,
|
||||
|
||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||
"Grabbing all keys on window %s\n", window->desc);
|
||||
retval = grab_keyboard (window->display, grabwindow, timestamp);
|
||||
retval = grab_keyboard (window->display, grabwindow, timestamp, XIGrabModeAsync);
|
||||
if (retval)
|
||||
{
|
||||
window->keys_grabbed = FALSE;
|
||||
@@ -1419,6 +1616,32 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp)
|
||||
{
|
||||
grab_keyboard (display, window, timestamp, XIGrabModeSync);
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_ungrab_keyboard (MetaDisplay *display, guint32 timestamp)
|
||||
{
|
||||
ungrab_keyboard (display, timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_unfreeze_keyboard (MetaDisplay *display, guint32 timestamp)
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XIAllowEvents (display->xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID,
|
||||
XIAsyncDevice, timestamp);
|
||||
/* We shouldn't need to unfreeze the pointer device here, however we
|
||||
* have to, due to the workaround we do in grab_keyboard().
|
||||
*/
|
||||
XIAllowEvents (display->xdisplay, META_VIRTUAL_CORE_POINTER_ID,
|
||||
XIAsyncDevice, timestamp);
|
||||
meta_error_trap_pop (display);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_modifier (MetaDisplay *display,
|
||||
unsigned int keycode)
|
||||
@@ -1747,6 +1970,23 @@ process_overlay_key (MetaDisplay *display,
|
||||
return TRUE;
|
||||
meta_display_overlay_key_activate (display);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In some rare race condition, mutter might not receive the Super_L
|
||||
* KeyRelease event because:
|
||||
* - the compositor might end the modal mode and call XIUngrabDevice
|
||||
* while the key is still down
|
||||
* - passive grabs are only activated on KeyPress and not KeyRelease.
|
||||
*
|
||||
* In this case, display->overlay_key_only_pressed might be wrong.
|
||||
* Mutter still ought to acknowledge events, otherwise the X server
|
||||
* will not send the next events.
|
||||
*
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=666101
|
||||
*/
|
||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||
XIAsyncDevice, event->time);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1765,6 +2005,41 @@ process_overlay_key (MetaDisplay *display,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_iso_next_group (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
XIDeviceEvent *event,
|
||||
KeySym keysym)
|
||||
{
|
||||
gboolean activate;
|
||||
unsigned int mods;
|
||||
int i;
|
||||
|
||||
if (event->evtype != XI_KeyPress)
|
||||
return FALSE;
|
||||
|
||||
activate = FALSE;
|
||||
mods = (event->mods.effective & 0xff & ~(display->ignored_modifier_mask));
|
||||
|
||||
for (i = 0; i < display->n_iso_next_group_combos; ++i)
|
||||
{
|
||||
if (event->detail == (int)display->iso_next_group_combos[i].keycode &&
|
||||
mods == display->iso_next_group_combos[i].modifiers)
|
||||
{
|
||||
/* If the signal handler returns TRUE the keyboard will
|
||||
remain frozen. It's the signal handler's responsibility
|
||||
to unfreeze it. */
|
||||
if (!meta_display_modifiers_accelerator_activate (display))
|
||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||
XIAsyncDevice, event->time);
|
||||
activate = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return activate;
|
||||
}
|
||||
|
||||
/* Handle a key event. May be called recursively: some key events cause
|
||||
* grabs to be ended and then need to be processed again in their own
|
||||
* right. This cannot cause infinite recursion because we never call
|
||||
@@ -1790,37 +2065,22 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
gboolean handled;
|
||||
const char *str;
|
||||
MetaScreen *screen;
|
||||
gboolean was_current_time;
|
||||
|
||||
if (all_bindings_disabled)
|
||||
{
|
||||
/* In this mode, we try to pretend we don't have grabs, so we
|
||||
* immediately replay events and drop the grab. (This still
|
||||
* messes up global passive grabs from other clients.) The
|
||||
* FALSE return here is a little suspect, but we don't really
|
||||
* know if we'll see the event again or not, and it's pretty
|
||||
* poorly defined how this mode is supposed to interact with
|
||||
* plugins.
|
||||
*/
|
||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||
XIReplayDevice, event->time);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* if key event was on root window, we have a shortcut */
|
||||
screen = meta_display_screen_for_root (display, event->event);
|
||||
|
||||
/* else round-trip to server */
|
||||
if (screen == NULL)
|
||||
screen = meta_display_screen_for_xwindow (display, event->event);
|
||||
|
||||
if (screen == NULL)
|
||||
return FALSE; /* event window is destroyed */
|
||||
/* We only ever have one screen */
|
||||
screen = display->screens->data;
|
||||
|
||||
/* ignore key events on popup menus and such. */
|
||||
if (meta_ui_window_is_widget (screen->ui, event->event))
|
||||
return FALSE;
|
||||
|
||||
/* window may be NULL */
|
||||
if (display->current_time == CurrentTime)
|
||||
{
|
||||
display->current_time = event->time;
|
||||
was_current_time = TRUE;
|
||||
}
|
||||
else
|
||||
was_current_time = FALSE;
|
||||
|
||||
keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0);
|
||||
|
||||
@@ -1838,7 +2098,11 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
{
|
||||
handled = process_overlay_key (display, screen, event, keysym);
|
||||
if (handled)
|
||||
return TRUE;
|
||||
goto out;
|
||||
|
||||
handled = process_iso_next_group (display, screen, event, keysym);
|
||||
if (handled)
|
||||
goto out;
|
||||
}
|
||||
|
||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||
@@ -1848,7 +2112,11 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
if (all_keys_grabbed)
|
||||
{
|
||||
if (display->grab_op == META_GRAB_OP_NONE)
|
||||
return TRUE;
|
||||
{
|
||||
handled = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we get here we have a global grab, because
|
||||
* we're in some special keyboard mode such as window move
|
||||
* mode.
|
||||
@@ -1927,14 +2195,20 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
meta_display_end_grab_op (display, event->time);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
handled = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Do the normal keybindings */
|
||||
return process_event (display->key_bindings,
|
||||
display->n_key_bindings,
|
||||
display, screen, window, event, keysym,
|
||||
!all_keys_grabbed && window);
|
||||
handled = process_event (display->key_bindings,
|
||||
display->n_key_bindings,
|
||||
display, screen, window, event, keysym,
|
||||
!all_keys_grabbed && window);
|
||||
|
||||
out:
|
||||
if (was_current_time)
|
||||
display->current_time = CurrentTime;
|
||||
return handled;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -3839,13 +4113,39 @@ handle_set_spew_mark (MetaDisplay *display,
|
||||
meta_verbose ("-- MARK MARK MARK MARK --\n");
|
||||
}
|
||||
|
||||
void
|
||||
meta_set_keybindings_disabled (gboolean setting)
|
||||
#ifdef HAVE_WAYLAND
|
||||
static void
|
||||
handle_switch_vt (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaWindow *window,
|
||||
XIDeviceEvent *event,
|
||||
MetaKeyBinding *binding,
|
||||
gpointer dummy)
|
||||
{
|
||||
all_bindings_disabled = setting;
|
||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||
"Keybindings %s\n", all_bindings_disabled ? "disabled" : "enabled");
|
||||
gint vt = binding->handler->data;
|
||||
MetaWaylandCompositor *compositor;
|
||||
MetaLauncher *launcher;
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
launcher = meta_wayland_compositor_get_launcher (compositor);
|
||||
|
||||
if (launcher)
|
||||
{
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
if (!meta_launcher_activate_vt (launcher, vt, &error))
|
||||
{
|
||||
g_warning ("Failed to switch VT: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Ignoring VT switch keybinding, not running as VT manager");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* meta_keybindings_set_custom_handler:
|
||||
@@ -3910,6 +4210,7 @@ init_builtin_key_bindings (MetaDisplay *display)
|
||||
META_KEY_BINDING_IS_REVERSED)
|
||||
GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS);
|
||||
GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS);
|
||||
GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-workspace-1",
|
||||
@@ -4171,6 +4472,60 @@ init_builtin_key_bindings (MetaDisplay *display)
|
||||
META_KEYBINDING_ACTION_SET_SPEW_MARK,
|
||||
handle_set_spew_mark, 0);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-1",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 1);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-2",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 2);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-3",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 3);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-4",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 4);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-5",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 5);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-6",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 6);
|
||||
|
||||
add_builtin_keybinding (display,
|
||||
"switch-to-session-7",
|
||||
mutter_wayland_keybindings,
|
||||
META_KEY_BINDING_NONE,
|
||||
META_KEYBINDING_ACTION_NONE,
|
||||
handle_switch_vt, 7);
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef REVERSES_AND_REVERSED
|
||||
|
||||
/************************ PER WINDOW BINDINGS ************************/
|
||||
@@ -4532,6 +4887,12 @@ meta_display_init_keys (MetaDisplay *display)
|
||||
|
||||
g_hash_table_insert (key_handlers, g_strdup ("overlay-key"), handler);
|
||||
|
||||
handler = g_new0 (MetaKeyHandler, 1);
|
||||
handler->name = g_strdup ("iso-next-group");
|
||||
handler->flags = META_KEY_BINDING_BUILTIN;
|
||||
|
||||
g_hash_table_insert (key_handlers, g_strdup ("iso-next-group"), handler);
|
||||
|
||||
handler = g_new0 (MetaKeyHandler, 1);
|
||||
handler->name = g_strdup ("external-grab");
|
||||
handler->func = handle_external_grab;
|
||||
|
@@ -55,8 +55,10 @@
|
||||
#include "session.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/compositor.h>
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib-unix.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -247,6 +249,17 @@ meta_get_option_context (void)
|
||||
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
|
||||
/* We must set the variables here, because Clutter creates the backend
|
||||
when the first call is made.
|
||||
|
||||
We consider running from mutter-launch equivalent to running from bare metal.
|
||||
*/
|
||||
if (getenv ("WESTON_LAUNCHER_SOCK"))
|
||||
{
|
||||
g_setenv ("CLUTTER_BACKEND", "eglnative", TRUE);
|
||||
g_setenv ("CLUTTER_INPUT_BACKEND", "evdev", TRUE);
|
||||
}
|
||||
|
||||
ctx = g_option_context_new (NULL);
|
||||
g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE);
|
||||
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
|
||||
@@ -346,28 +359,17 @@ meta_finalize (void)
|
||||
if (display)
|
||||
meta_display_close (display,
|
||||
CurrentTime); /* I doubt correct timestamps matter here */
|
||||
}
|
||||
|
||||
static int sigterm_pipe_fds[2] = { -1, -1 };
|
||||
|
||||
static void
|
||||
sigterm_handler (int signum)
|
||||
{
|
||||
if (sigterm_pipe_fds[1] >= 0)
|
||||
{
|
||||
int G_GNUC_UNUSED dummy;
|
||||
|
||||
dummy = write (sigterm_pipe_fds[1], "", 1);
|
||||
close (sigterm_pipe_fds[1]);
|
||||
sigterm_pipe_fds[1] = -1;
|
||||
}
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_wayland_finalize ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_sigterm (void)
|
||||
on_sigterm (gpointer user_data)
|
||||
{
|
||||
meta_quit (META_EXIT_SUCCESS);
|
||||
return FALSE;
|
||||
meta_quit (EXIT_SUCCESS);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,7 +383,6 @@ meta_init (void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigset_t empty_mask;
|
||||
GIOChannel *channel;
|
||||
|
||||
sigemptyset (&empty_mask);
|
||||
act.sa_handler = SIG_IGN;
|
||||
@@ -396,20 +397,10 @@ meta_init (void)
|
||||
g_strerror (errno));
|
||||
#endif
|
||||
|
||||
if (pipe (sigterm_pipe_fds) != 0)
|
||||
g_printerr ("Failed to create SIGTERM pipe: %s\n",
|
||||
g_strerror (errno));
|
||||
if (getenv ("MUTTER_SLEEP_INIT"))
|
||||
sleep (60);
|
||||
|
||||
channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
|
||||
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
|
||||
g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL);
|
||||
g_io_channel_set_close_on_unref (channel, TRUE);
|
||||
g_io_channel_unref (channel);
|
||||
|
||||
act.sa_handler = &sigterm_handler;
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||
g_printerr ("Failed to register SIGTERM handler: %s\n",
|
||||
g_strerror (errno));
|
||||
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
|
||||
|
||||
if (g_getenv ("MUTTER_VERBOSE"))
|
||||
meta_set_verbose (TRUE);
|
||||
@@ -427,9 +418,16 @@ meta_init (void)
|
||||
g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
|
||||
#endif
|
||||
|
||||
meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
|
||||
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_select_display (opt_display_name);
|
||||
|
||||
meta_select_display (opt_display_name);
|
||||
meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
|
||||
|
||||
if (opt_replace_wm)
|
||||
meta_set_replace_current_wm (TRUE);
|
||||
@@ -441,10 +439,17 @@ meta_init (void)
|
||||
|
||||
meta_ui_init ();
|
||||
|
||||
/*
|
||||
* Clutter can only be initialized after the UI.
|
||||
*/
|
||||
meta_clutter_init ();
|
||||
/* If we are running with wayland then we don't wait until we have
|
||||
* an X connection before initializing clutter we instead initialize
|
||||
* it earlier since we need to initialize the GL driver so the driver
|
||||
* can register any needed wayland extensions. */
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
/*
|
||||
* Clutter can only be initialized after the UI.
|
||||
*/
|
||||
meta_clutter_init ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,14 +519,14 @@ meta_run (void)
|
||||
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 (), FALSE);
|
||||
meta_ui_set_current_theme (meta_prefs_get_theme ());
|
||||
|
||||
/* Try to find some theme that'll work if the theme preference
|
||||
* doesn't exist. First try Simple (the default theme) then just
|
||||
* try anything in the themes directory.
|
||||
*/
|
||||
if (!meta_ui_have_a_theme ())
|
||||
meta_ui_set_current_theme ("Simple", FALSE);
|
||||
meta_ui_set_current_theme ("Simple");
|
||||
|
||||
if (!meta_ui_have_a_theme ())
|
||||
{
|
||||
@@ -539,7 +544,7 @@ meta_run (void)
|
||||
while (((dir_entry = g_dir_read_name (themes_dir)) != NULL) &&
|
||||
(!meta_ui_have_a_theme ()))
|
||||
{
|
||||
meta_ui_set_current_theme (dir_entry, FALSE);
|
||||
meta_ui_set_current_theme (dir_entry);
|
||||
}
|
||||
|
||||
g_dir_close (themes_dir);
|
||||
@@ -598,7 +603,7 @@ prefs_changed_callback (MetaPreference pref,
|
||||
{
|
||||
case META_PREF_THEME:
|
||||
case META_PREF_DRAGGABLE_BORDER_WIDTH:
|
||||
meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE);
|
||||
meta_ui_set_current_theme (meta_prefs_get_theme ());
|
||||
meta_display_retheme_all ();
|
||||
break;
|
||||
|
||||
|
47
src/core/meta-cursor-tracker-private.h
Normal file
47
src/core/meta-cursor-tracker-private.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef META_CURSOR_TRACKER_PRIVATE_H
|
||||
#define META_CURSOR_TRACKER_PRIVATE_H
|
||||
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||
XEvent *xevent);
|
||||
|
||||
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||
MetaCursor cursor);
|
||||
void meta_cursor_tracker_revert_root (MetaCursorTracker *tracker);
|
||||
void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
|
||||
CoglTexture2D *texture,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
|
||||
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
|
||||
int new_x,
|
||||
int new_y);
|
||||
void meta_cursor_tracker_paint (MetaCursorTracker *tracker);
|
||||
void meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
|
||||
ClutterActor *stage);
|
||||
#endif
|
458
src/core/meta-cursor-tracker.c
Normal file
458
src/core/meta-cursor-tracker.c
Normal file
@@ -0,0 +1,458 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:cursor-tracker
|
||||
* @title: MetaCursorTracker
|
||||
* @short_description: Mutter cursor tracking helper
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/util.h>
|
||||
#include <meta/errors.h>
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "screen-private.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "meta-wayland-private.h"
|
||||
#endif
|
||||
|
||||
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
|
||||
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
|
||||
|
||||
struct _MetaCursorTracker {
|
||||
GObject parent_instance;
|
||||
|
||||
MetaScreen *screen;
|
||||
|
||||
gboolean is_showing;
|
||||
|
||||
CoglTexture2D *sprite;
|
||||
int hot_x, hot_y;
|
||||
|
||||
CoglTexture2D *root_cursor;
|
||||
int root_hot_x, root_hot_y;
|
||||
|
||||
CoglTexture2D *default_cursor;
|
||||
|
||||
int current_x, current_y;
|
||||
cairo_rectangle_int_t current_rect;
|
||||
cairo_rectangle_int_t previous_rect;
|
||||
gboolean previous_is_valid;
|
||||
|
||||
CoglPipeline *pipeline;
|
||||
};
|
||||
|
||||
struct _MetaCursorTrackerClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
CURSOR_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_init (MetaCursorTracker *self)
|
||||
{
|
||||
/* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of
|
||||
detecting if the system mouse cursor is showing or not.
|
||||
|
||||
On wayland we start with the cursor showing
|
||||
*/
|
||||
self->is_showing = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_finalize (GObject *object)
|
||||
{
|
||||
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
|
||||
|
||||
if (self->sprite)
|
||||
cogl_object_unref (self->sprite);
|
||||
if (self->root_cursor)
|
||||
cogl_object_unref (self->root_cursor);
|
||||
if (self->default_cursor)
|
||||
cogl_object_unref (self->default_cursor);
|
||||
if (self->pipeline)
|
||||
cogl_object_unref (self->pipeline);
|
||||
|
||||
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_cursor_tracker_finalize;
|
||||
|
||||
signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
static MetaCursorTracker *
|
||||
make_wayland_cursor_tracker (MetaScreen *screen)
|
||||
{
|
||||
MetaWaylandCompositor *compositor;
|
||||
CoglContext *ctx;
|
||||
MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
self->pipeline = cogl_pipeline_new (ctx);
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
compositor->seat->cursor_tracker = self;
|
||||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
static MetaCursorTracker *
|
||||
make_x11_cursor_tracker (MetaScreen *screen)
|
||||
{
|
||||
MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
|
||||
XFixesSelectCursorInput (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
XFixesDisplayCursorNotifyMask);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_for_screen:
|
||||
* @screen: the #MetaScreen
|
||||
*
|
||||
* Retrieves the cursor tracker object for @screen.
|
||||
*
|
||||
* Returns: (transfer none):
|
||||
*/
|
||||
MetaCursorTracker *
|
||||
meta_cursor_tracker_get_for_screen (MetaScreen *screen)
|
||||
{
|
||||
MetaCursorTracker *self;
|
||||
|
||||
if (screen->cursor_tracker)
|
||||
return screen->cursor_tracker;
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor ())
|
||||
self = make_wayland_cursor_tracker (screen);
|
||||
else
|
||||
#endif
|
||||
self = make_x11_cursor_tracker (screen);
|
||||
|
||||
screen->cursor_tracker = self;
|
||||
return self;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||
XEvent *xevent)
|
||||
{
|
||||
XFixesCursorNotifyEvent *notify_event;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
return FALSE;
|
||||
|
||||
if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify)
|
||||
return FALSE;
|
||||
|
||||
notify_event = (XFixesCursorNotifyEvent *)xevent;
|
||||
if (notify_event->subtype != XFixesDisplayCursorNotify)
|
||||
return FALSE;
|
||||
|
||||
g_clear_pointer (&tracker->sprite, cogl_object_unref);
|
||||
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
XFixesCursorImage *cursor_image;
|
||||
CoglTexture2D *sprite;
|
||||
guint8 *cursor_data;
|
||||
gboolean free_cursor_data;
|
||||
CoglContext *ctx;
|
||||
|
||||
if (tracker->sprite)
|
||||
return;
|
||||
|
||||
cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay);
|
||||
if (!cursor_image)
|
||||
return;
|
||||
|
||||
/* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
|
||||
* quantities as arrays of long; we need to convert on 64 bit */
|
||||
if (sizeof(long) == 4)
|
||||
{
|
||||
cursor_data = (guint8 *)cursor_image->pixels;
|
||||
free_cursor_data = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, j;
|
||||
guint32 *cursor_words;
|
||||
gulong *p;
|
||||
guint32 *q;
|
||||
|
||||
cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
|
||||
cursor_data = (guint8 *)cursor_words;
|
||||
|
||||
p = cursor_image->pixels;
|
||||
q = cursor_words;
|
||||
for (j = 0; j < cursor_image->height; j++)
|
||||
for (i = 0; i < cursor_image->width; i++)
|
||||
*(q++) = *(p++);
|
||||
|
||||
free_cursor_data = TRUE;
|
||||
}
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
sprite = cogl_texture_2d_new_from_data (ctx,
|
||||
cursor_image->width,
|
||||
cursor_image->height,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
cursor_image->width * 4, /* stride */
|
||||
cursor_data,
|
||||
NULL);
|
||||
|
||||
if (free_cursor_data)
|
||||
g_free (cursor_data);
|
||||
|
||||
if (sprite != NULL)
|
||||
{
|
||||
tracker->sprite = sprite;
|
||||
tracker->hot_x = cursor_image->xhot;
|
||||
tracker->hot_y = cursor_image->yhot;
|
||||
}
|
||||
XFree (cursor_image);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_sprite:
|
||||
*
|
||||
* Returns: (transfer none):
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
ensure_xfixes_cursor (tracker);
|
||||
|
||||
return COGL_TEXTURE (tracker->sprite);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_hot:
|
||||
* @tracker:
|
||||
* @x: (out):
|
||||
* @y: (out):
|
||||
*
|
||||
*/
|
||||
void
|
||||
meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
||||
int *x,
|
||||
int *y)
|
||||
{
|
||||
g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
ensure_xfixes_cursor (tracker);
|
||||
|
||||
if (x)
|
||||
*x = tracker->hot_x;
|
||||
if (y)
|
||||
*y = tracker->hot_y;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_wayland_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
CoglBitmap *bitmap;
|
||||
char *filename;
|
||||
|
||||
if (tracker->default_cursor)
|
||||
return;
|
||||
|
||||
filename = g_build_filename (MUTTER_PKGDATADIR,
|
||||
"cursors/left_ptr.png",
|
||||
NULL);
|
||||
|
||||
bitmap = cogl_bitmap_new_from_file (filename, NULL);
|
||||
tracker->default_cursor = cogl_texture_2d_new_from_bitmap (bitmap,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
NULL);
|
||||
|
||||
cogl_object_unref (bitmap);
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
Cursor xcursor;
|
||||
MetaDisplay *display = tracker->screen->display;
|
||||
|
||||
/* First create a cursor for X11 applications that don't specify their own */
|
||||
xcursor = meta_display_create_x_cursor (display, cursor);
|
||||
|
||||
XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor);
|
||||
XFlush (display->xdisplay);
|
||||
XFreeCursor (display->xdisplay, xcursor);
|
||||
|
||||
/* Now update the real root cursor */
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* FIXME! We need to load all the other cursors too */
|
||||
ensure_wayland_cursor (tracker);
|
||||
|
||||
g_clear_pointer (&tracker->root_cursor, cogl_object_unref);
|
||||
tracker->root_cursor = cogl_object_ref (tracker->default_cursor);
|
||||
tracker->root_hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
|
||||
tracker->root_hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_revert_root (MetaCursorTracker *tracker)
|
||||
{
|
||||
meta_cursor_tracker_set_sprite (tracker,
|
||||
tracker->root_cursor,
|
||||
tracker->root_hot_x,
|
||||
tracker->root_hot_y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
|
||||
CoglTexture2D *sprite,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
g_clear_pointer (&tracker->sprite, cogl_object_unref);
|
||||
|
||||
if (sprite)
|
||||
{
|
||||
tracker->sprite = cogl_object_ref (sprite);
|
||||
tracker->hot_x = hot_x;
|
||||
tracker->hot_y = hot_y;
|
||||
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite));
|
||||
}
|
||||
else
|
||||
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
|
||||
|
||||
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
||||
|
||||
meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
|
||||
int new_x,
|
||||
int new_y)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
tracker->current_x = new_x;
|
||||
tracker->current_y = new_y;
|
||||
tracker->current_rect.x = tracker->current_x - tracker->hot_x;
|
||||
tracker->current_rect.y = tracker->current_y - tracker->hot_y;
|
||||
|
||||
if (tracker->sprite)
|
||||
{
|
||||
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite));
|
||||
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite));
|
||||
}
|
||||
else
|
||||
{
|
||||
tracker->current_rect.width = 0;
|
||||
tracker->current_rect.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_paint (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
if (tracker->sprite == NULL)
|
||||
return;
|
||||
|
||||
/* FIXME: try to use a DRM cursor when possible */
|
||||
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
|
||||
tracker->pipeline,
|
||||
tracker->current_rect.x,
|
||||
tracker->current_rect.y,
|
||||
tracker->current_rect.x +
|
||||
tracker->current_rect.width,
|
||||
tracker->current_rect.y +
|
||||
tracker->current_rect.height);
|
||||
|
||||
tracker->previous_rect = tracker->current_rect;
|
||||
tracker->previous_is_valid = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
|
||||
ClutterActor *stage)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
if (tracker->previous_is_valid)
|
||||
{
|
||||
clutter_actor_queue_redraw_with_clip (stage, &tracker->previous_rect);
|
||||
tracker->previous_is_valid = FALSE;
|
||||
}
|
||||
|
||||
if (tracker->sprite == NULL)
|
||||
return;
|
||||
|
||||
clutter_actor_queue_redraw_with_clip (stage, &tracker->current_rect);
|
||||
}
|
31
src/core/meta-idle-monitor-private.h
Normal file
31
src/core/meta-idle-monitor-private.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
|
||||
void meta_idle_monitor_handle_xevent_all (XEvent *xevent);
|
||||
|
||||
void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor);
|
||||
|
||||
void meta_idle_monitor_init_dbus (void);
|
965
src/core/meta-idle-monitor.c
Normal file
965
src/core/meta-idle-monitor.c
Normal file
@@ -0,0 +1,965 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:idle-monitor
|
||||
* @title: MetaIdleMonitor
|
||||
* @short_description: Mutter idle counter (similar to X's IDLETIME)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
#include <meta/util.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "display-private.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-dbus-idle-monitor.h"
|
||||
|
||||
G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
|
||||
|
||||
struct _MetaIdleMonitor
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *watches;
|
||||
GHashTable *alarms;
|
||||
int device_id;
|
||||
|
||||
/* X11 implementation */
|
||||
Display *display;
|
||||
int sync_event_base;
|
||||
XSyncCounter counter;
|
||||
XSyncAlarm user_active_alarm;
|
||||
|
||||
/* Wayland implementation */
|
||||
guint64 last_event_time;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
guint id;
|
||||
MetaIdleMonitorWatchFunc callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
guint64 timeout_msec;
|
||||
|
||||
/* x11 */
|
||||
XSyncAlarm xalarm;
|
||||
|
||||
/* wayland */
|
||||
GSource *timeout_source;
|
||||
} MetaIdleMonitorWatch;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DEVICE_ID,
|
||||
PROP_LAST,
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST];
|
||||
|
||||
G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT)
|
||||
|
||||
static MetaIdleMonitor *device_monitors[256];
|
||||
static int device_id_max;
|
||||
|
||||
static gint64
|
||||
_xsyncvalue_to_int64 (XSyncValue value)
|
||||
{
|
||||
return ((guint64) XSyncValueHigh32 (value)) << 32
|
||||
| (guint64) XSyncValueLow32 (value);
|
||||
}
|
||||
|
||||
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
|
||||
|
||||
static void
|
||||
fire_watch (MetaIdleMonitorWatch *watch)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
guint id;
|
||||
gboolean is_user_active_watch;
|
||||
|
||||
monitor = watch->monitor;
|
||||
g_object_ref (monitor);
|
||||
|
||||
id = watch->id;
|
||||
is_user_active_watch = (watch->timeout_msec == 0);
|
||||
|
||||
if (watch->callback)
|
||||
watch->callback (monitor, id, watch->user_data);
|
||||
|
||||
if (is_user_active_watch)
|
||||
meta_idle_monitor_remove_watch (monitor, id);
|
||||
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
|
||||
static XSyncAlarm
|
||||
_xsync_alarm_set (MetaIdleMonitor *monitor,
|
||||
XSyncTestType test_type,
|
||||
guint64 interval,
|
||||
gboolean want_events)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
XSyncValue delta;
|
||||
guint flags;
|
||||
|
||||
flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
|
||||
XSyncCAValue | XSyncCADelta | XSyncCAEvents;
|
||||
|
||||
XSyncIntToValue (&delta, 0);
|
||||
attr.trigger.counter = monitor->counter;
|
||||
attr.trigger.value_type = XSyncAbsolute;
|
||||
attr.delta = delta;
|
||||
attr.events = want_events;
|
||||
|
||||
GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
|
||||
attr.trigger.test_type = test_type;
|
||||
return XSyncCreateAlarm (monitor->display, flags, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_alarm_rescheduled (Display *dpy,
|
||||
XSyncAlarm alarm)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
|
||||
/* Some versions of Xorg have an issue where alarms aren't
|
||||
* always rescheduled. Calling XSyncChangeAlarm, even
|
||||
* without any attributes, will reschedule the alarm. */
|
||||
XSyncChangeAlarm (dpy, alarm, 0, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
set_alarm_enabled (Display *dpy,
|
||||
XSyncAlarm alarm,
|
||||
gboolean enabled)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
attr.events = enabled;
|
||||
XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
check_x11_watch (gpointer data,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = data;
|
||||
XSyncAlarm alarm = (XSyncAlarm) user_data;
|
||||
|
||||
if (watch->xalarm != alarm)
|
||||
return;
|
||||
|
||||
fire_watch (watch);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_handle_xevent (MetaIdleMonitor *monitor,
|
||||
XSyncAlarmNotifyEvent *alarm_event)
|
||||
{
|
||||
XSyncAlarm alarm;
|
||||
GList *watches;
|
||||
gboolean has_alarm;
|
||||
|
||||
if (alarm_event->state != XSyncAlarmActive)
|
||||
return;
|
||||
|
||||
alarm = alarm_event->alarm;
|
||||
|
||||
has_alarm = FALSE;
|
||||
|
||||
if (alarm == monitor->user_active_alarm)
|
||||
{
|
||||
set_alarm_enabled (monitor->display,
|
||||
alarm,
|
||||
FALSE);
|
||||
has_alarm = TRUE;
|
||||
}
|
||||
else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm))
|
||||
{
|
||||
ensure_alarm_rescheduled (monitor->display,
|
||||
alarm);
|
||||
has_alarm = TRUE;
|
||||
}
|
||||
|
||||
if (has_alarm)
|
||||
{
|
||||
watches = g_hash_table_get_values (monitor->watches);
|
||||
|
||||
g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
|
||||
g_list_free (watches);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_handle_xevent_all (XEvent *xevent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= device_id_max; i++)
|
||||
if (device_monitors[i])
|
||||
meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent);
|
||||
}
|
||||
|
||||
static char *
|
||||
counter_name_for_device (int device_id)
|
||||
{
|
||||
if (device_id > 0)
|
||||
return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
|
||||
|
||||
return g_strdup ("IDLETIME");
|
||||
}
|
||||
|
||||
static XSyncCounter
|
||||
find_idletime_counter (MetaIdleMonitor *monitor)
|
||||
{
|
||||
int i;
|
||||
int ncounters;
|
||||
XSyncSystemCounter *counters;
|
||||
XSyncCounter counter = None;
|
||||
char *counter_name;
|
||||
|
||||
counter_name = counter_name_for_device (monitor->device_id);
|
||||
counters = XSyncListSystemCounters (monitor->display, &ncounters);
|
||||
for (i = 0; i < ncounters; i++)
|
||||
{
|
||||
if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0)
|
||||
{
|
||||
counter = counters[i].counter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XSyncFreeSystemCounterList (counters);
|
||||
g_free (counter_name);
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
static guint32 serial = 0;
|
||||
g_atomic_int_inc (&serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static void
|
||||
idle_monitor_watch_free (MetaIdleMonitorWatch *watch)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
|
||||
if (watch == NULL)
|
||||
return;
|
||||
|
||||
monitor = watch->monitor;
|
||||
|
||||
if (watch->notify != NULL)
|
||||
watch->notify (watch->user_data);
|
||||
|
||||
if (watch->xalarm != monitor->user_active_alarm &&
|
||||
watch->xalarm != None)
|
||||
{
|
||||
XSyncDestroyAlarm (monitor->display, watch->xalarm);
|
||||
g_hash_table_remove (monitor->alarms, (gpointer) watch->xalarm);
|
||||
}
|
||||
|
||||
if (watch->timeout_source != NULL)
|
||||
g_source_destroy (watch->timeout_source);
|
||||
|
||||
g_slice_free (MetaIdleMonitorWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
init_xsync (MetaIdleMonitor *monitor)
|
||||
{
|
||||
monitor->counter = find_idletime_counter (monitor);
|
||||
/* IDLETIME counter not found? */
|
||||
if (monitor->counter == None)
|
||||
{
|
||||
meta_warning ("IDLETIME counter not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_dispose (GObject *object)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
|
||||
monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
g_clear_pointer (&monitor->watches, g_hash_table_destroy);
|
||||
g_clear_pointer (&monitor->alarms, g_hash_table_destroy);
|
||||
|
||||
if (monitor->user_active_alarm != None)
|
||||
{
|
||||
XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm);
|
||||
monitor->user_active_alarm = None;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE_ID:
|
||||
g_value_set_int (value, monitor->device_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE_ID:
|
||||
monitor->device_id = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_constructed (GObject *object)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
monitor->display = meta_get_display ()->xdisplay;
|
||||
init_xsync (monitor);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_idle_monitor_dispose;
|
||||
object_class->constructed = meta_idle_monitor_constructed;
|
||||
object_class->get_property = meta_idle_monitor_get_property;
|
||||
object_class->set_property = meta_idle_monitor_set_property;
|
||||
|
||||
/**
|
||||
* MetaIdleMonitor:device_id:
|
||||
*
|
||||
* The device to listen to idletime on.
|
||||
*/
|
||||
obj_props[PROP_DEVICE_ID] =
|
||||
g_param_spec_int ("device-id",
|
||||
"Device ID",
|
||||
"The device to listen to idletime on",
|
||||
0, 255, 0,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_init (MetaIdleMonitor *monitor)
|
||||
{
|
||||
monitor->watches = g_hash_table_new_full (NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GDestroyNotify)idle_monitor_watch_free);
|
||||
|
||||
monitor->alarms = g_hash_table_new (NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_device_monitor (int device_id)
|
||||
{
|
||||
if (device_monitors[device_id])
|
||||
return;
|
||||
|
||||
device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL);
|
||||
device_id_max = MAX (device_id_max, device_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_core:
|
||||
*
|
||||
* Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global
|
||||
* idletime for all devices. To track device-specific idletime,
|
||||
* use meta_idle_monitor_get_for_device().
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_idle_monitor_get_core (void)
|
||||
{
|
||||
ensure_device_monitor (0);
|
||||
return device_monitors[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_for_device:
|
||||
* @device_id: the device to get the idle time for.
|
||||
*
|
||||
* Returns: (transfer none): a new #MetaIdleMonitor that tracks the
|
||||
* device-specific idletime for @device. To track server-global idletime
|
||||
* for all devices, use meta_idle_monitor_get_core().
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_idle_monitor_get_for_device (int device_id)
|
||||
{
|
||||
g_return_val_if_fail (device_id > 0 && device_id < 256, NULL);
|
||||
|
||||
ensure_device_monitor (device_id);
|
||||
return device_monitors[device_id];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wayland_dispatch_timeout (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = user_data;
|
||||
|
||||
fire_watch (watch);
|
||||
g_source_set_ready_time (watch->timeout_source, -1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs wayland_source_funcs = {
|
||||
NULL, /* prepare */
|
||||
NULL, /* check */
|
||||
wayland_dispatch_timeout,
|
||||
NULL, /* finalize */
|
||||
};
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
watch = g_slice_new0 (MetaIdleMonitorWatch);
|
||||
watch->monitor = monitor;
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
watch->timeout_msec = timeout_msec;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
GSource *source = g_source_new (&wayland_source_funcs, sizeof (GSource));
|
||||
|
||||
g_source_set_callback (source, NULL, watch, NULL);
|
||||
g_source_set_ready_time (source, monitor->last_event_time + timeout_msec * 1000);
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
|
||||
watch->timeout_source = source;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE);
|
||||
|
||||
g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm);
|
||||
}
|
||||
else
|
||||
{
|
||||
watch->xalarm = monitor->user_active_alarm;
|
||||
|
||||
set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_insert (monitor->watches,
|
||||
GUINT_TO_POINTER (watch->id),
|
||||
watch);
|
||||
return watch;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_add_idle_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @interval_msec: The idletime interval, in milliseconds
|
||||
* @callback: (allow-none): The callback to call when the user has
|
||||
* accumulated @interval_msec milliseconds of idle time.
|
||||
* @user_data: (allow-none): The user data to pass to the callback
|
||||
* @notify: A #GDestroyNotify
|
||||
*
|
||||
* Returns: a watch id
|
||||
*
|
||||
* Adds a watch for a specific idle time. The callback will be called
|
||||
* when the user has accumulated @interval_msec milliseconds of idle time.
|
||||
* This function will return an ID that can either be passed to
|
||||
* meta_idle_monitor_remove_watch(), or can be used to tell idle time
|
||||
* watches apart if you have more than one.
|
||||
*
|
||||
* Also note that this function will only care about positive transitions
|
||||
* (user's idle time exceeding a certain time). If you want to know about
|
||||
* when the user has become active, use
|
||||
* meta_idle_monitor_add_user_active_watch().
|
||||
*/
|
||||
guint
|
||||
meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor,
|
||||
guint64 interval_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
|
||||
g_return_val_if_fail (interval_msec > 0, 0);
|
||||
|
||||
watch = make_watch (monitor,
|
||||
interval_msec,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_add_user_active_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @callback: (allow-none): The callback to call when the user is
|
||||
* active again.
|
||||
* @user_data: (allow-none): The user data to pass to the callback
|
||||
* @notify: A #GDestroyNotify
|
||||
*
|
||||
* Returns: a watch id
|
||||
*
|
||||
* Add a one-time watch to know when the user is active again.
|
||||
* Note that this watch is one-time and will de-activate after the
|
||||
* function is called, for efficiency purposes. It's most convenient
|
||||
* to call this when an idle watch, as added by
|
||||
* meta_idle_monitor_add_idle_watch(), has triggered.
|
||||
*/
|
||||
guint
|
||||
meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
|
||||
|
||||
watch = make_watch (monitor,
|
||||
0,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_remove_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @id: A watch ID
|
||||
*
|
||||
* Removes an idle time watcher, previously added by
|
||||
* meta_idle_monitor_add_idle_watch() or
|
||||
* meta_idle_monitor_add_user_active_watch().
|
||||
*/
|
||||
void
|
||||
meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
|
||||
guint id)
|
||||
{
|
||||
g_return_if_fail (META_IS_IDLE_MONITOR (monitor));
|
||||
|
||||
g_hash_table_remove (monitor->watches,
|
||||
GUINT_TO_POINTER (id));
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_idletime:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
*
|
||||
* Returns: The current idle time, in milliseconds, or -1 for not supported
|
||||
*/
|
||||
gint64
|
||||
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
XSyncValue value;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
return (g_get_monotonic_time () - monitor->last_event_time) / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!XSyncQueryCounter (monitor->display, monitor->counter, &value))
|
||||
return -1;
|
||||
|
||||
return _xsyncvalue_to_int64 (value);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaIdleMonitor *monitor;
|
||||
GList *fired_watches;
|
||||
} CheckWaylandClosure;
|
||||
|
||||
static gboolean
|
||||
check_wayland_watch (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = value;
|
||||
CheckWaylandClosure *closure = user_data;
|
||||
gboolean steal;
|
||||
|
||||
if (watch->timeout_msec == 0)
|
||||
{
|
||||
closure->fired_watches = g_list_prepend (closure->fired_watches, watch);
|
||||
steal = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source,
|
||||
closure->monitor->last_event_time +
|
||||
watch->timeout_msec * 1000);
|
||||
steal = FALSE;
|
||||
}
|
||||
|
||||
return steal;
|
||||
}
|
||||
|
||||
static void
|
||||
fire_wayland_watch (gpointer watch,
|
||||
gpointer data)
|
||||
{
|
||||
fire_watch (watch);
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
CheckWaylandClosure closure;
|
||||
|
||||
monitor->last_event_time = g_get_monotonic_time ();
|
||||
|
||||
closure.monitor = monitor;
|
||||
closure.fired_watches = NULL;
|
||||
g_hash_table_foreach_steal (monitor->watches, check_wayland_watch, &closure);
|
||||
|
||||
g_list_foreach (closure.fired_watches, fire_wayland_watch, NULL);
|
||||
g_list_free (closure.fired_watches);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_get_idletime (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
guint64 idletime;
|
||||
|
||||
idletime = meta_idle_monitor_get_idletime (monitor);
|
||||
meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaDBusIdleMonitor *dbus_monitor;
|
||||
MetaIdleMonitor *monitor;
|
||||
char *dbus_name;
|
||||
guint watch_id;
|
||||
guint name_watcher_id;
|
||||
} DBusWatch;
|
||||
|
||||
static void
|
||||
destroy_dbus_watch (gpointer data)
|
||||
{
|
||||
DBusWatch *watch = data;
|
||||
|
||||
g_object_unref (watch->dbus_monitor);
|
||||
g_object_unref (watch->monitor);
|
||||
g_free (watch->dbus_name);
|
||||
g_bus_unwatch_name (watch->name_watcher_id);
|
||||
|
||||
g_slice_free (DBusWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_idle_callback (MetaIdleMonitor *monitor,
|
||||
guint watch_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
DBusWatch *watch = user_data;
|
||||
GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor);
|
||||
|
||||
g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton),
|
||||
watch->dbus_name,
|
||||
g_dbus_interface_skeleton_get_object_path (skeleton),
|
||||
"org.gnome.Mutter.IdleMonitor",
|
||||
"WatchFired",
|
||||
g_variant_new ("(u)", watch_id),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
name_vanished_callback (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
DBusWatch *watch = user_data;
|
||||
|
||||
meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id);
|
||||
}
|
||||
|
||||
static DBusWatch *
|
||||
make_dbus_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = g_slice_new (DBusWatch);
|
||||
watch->dbus_monitor = g_object_ref (skeleton);
|
||||
watch->monitor = g_object_ref (monitor);
|
||||
watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
|
||||
watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
|
||||
watch->dbus_name,
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
NULL, /* appeared */
|
||||
name_vanished_callback,
|
||||
watch, NULL);
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_idle_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint64 interval,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = make_dbus_watch (skeleton, invocation, monitor);
|
||||
watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval,
|
||||
dbus_idle_callback, watch, destroy_dbus_watch);
|
||||
|
||||
meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = make_dbus_watch (skeleton, invocation, monitor);
|
||||
watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor,
|
||||
dbus_idle_callback, watch,
|
||||
destroy_dbus_watch);
|
||||
|
||||
meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_remove_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint id,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
meta_idle_monitor_remove_watch (monitor, id);
|
||||
meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
create_monitor_skeleton (GDBusObjectManagerServer *manager,
|
||||
MetaIdleMonitor *monitor,
|
||||
const char *path)
|
||||
{
|
||||
MetaDBusIdleMonitor *skeleton;
|
||||
MetaDBusObjectSkeleton *object;
|
||||
|
||||
skeleton = meta_dbus_idle_monitor_skeleton_new ();
|
||||
g_signal_connect_object (skeleton, "handle-add-idle-watch",
|
||||
G_CALLBACK (handle_add_idle_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-add-user-active-watch",
|
||||
G_CALLBACK (handle_add_user_active_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-remove-watch",
|
||||
G_CALLBACK (handle_remove_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-get-idletime",
|
||||
G_CALLBACK (handle_get_idletime), monitor, 0);
|
||||
|
||||
object = meta_dbus_object_skeleton_new (path);
|
||||
meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
|
||||
|
||||
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_added (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
GDBusObjectManagerServer *manager)
|
||||
{
|
||||
|
||||
MetaIdleMonitor *monitor;
|
||||
int device_id;
|
||||
char *path;
|
||||
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
monitor = meta_idle_monitor_get_for_device (device_id);
|
||||
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
|
||||
|
||||
create_monitor_skeleton (manager, monitor, path);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_removed (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
GDBusObjectManagerServer *manager)
|
||||
{
|
||||
int device_id;
|
||||
char *path;
|
||||
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
|
||||
g_dbus_object_manager_server_unexport (manager, path);
|
||||
g_free (path);
|
||||
|
||||
g_clear_object (&device_monitors[device_id]);
|
||||
if (device_id == device_id_max)
|
||||
device_id_max--;
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusObjectManagerServer *manager;
|
||||
ClutterDeviceManager *device_manager;
|
||||
MetaIdleMonitor *monitor;
|
||||
GSList *devices, *iter;
|
||||
char *path;
|
||||
|
||||
manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
|
||||
|
||||
/* We never clear the core monitor, as that's supposed to cumulate idle times from
|
||||
all devices */
|
||||
monitor = meta_idle_monitor_get_core ();
|
||||
path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
|
||||
create_monitor_skeleton (manager, monitor, path);
|
||||
g_free (path);
|
||||
|
||||
device_manager = clutter_device_manager_get_default ();
|
||||
devices = clutter_device_manager_list_devices (device_manager);
|
||||
|
||||
for (iter = devices; iter; iter = iter->next)
|
||||
on_device_added (device_manager, iter->data, manager);
|
||||
|
||||
g_signal_connect_object (device_manager, "device-added",
|
||||
G_CALLBACK (on_device_added), manager, 0);
|
||||
g_signal_connect_object (device_manager, "device-removed",
|
||||
G_CALLBACK (on_device_removed), manager, 0);
|
||||
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_verbose ("Acquired name %s\n", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_verbose ("Lost or failed to acquire name %s\n", name);
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_init_dbus (void)
|
||||
{
|
||||
static int dbus_name_id;
|
||||
|
||||
if (dbus_name_id > 0)
|
||||
return;
|
||||
|
||||
dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gnome.Mutter.IdleMonitor",
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
||||
(meta_get_replace_current_wm () ?
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
40
src/core/meta-xrandr-shared.h
Normal file
40
src/core/meta-xrandr-shared.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* This file is shared between mutter (src/core/meta-xrandr-shared.h)
|
||||
and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h).
|
||||
|
||||
The canonical place for all changes is mutter.
|
||||
|
||||
There should be no includes in this file.
|
||||
*/
|
||||
|
||||
#ifndef META_XRANDR_SHARED_H
|
||||
#define META_XRANDR_SHARED_H
|
||||
|
||||
typedef enum {
|
||||
META_POWER_SAVE_UNKNOWN = -1,
|
||||
META_POWER_SAVE_ON = 0,
|
||||
META_POWER_SAVE_STANDBY,
|
||||
META_POWER_SAVE_SUSPEND,
|
||||
META_POWER_SAVE_OFF,
|
||||
} MetaPowerSave;
|
||||
|
||||
#endif
|
1808
src/core/monitor-config.c
Normal file
1808
src/core/monitor-config.c
Normal file
File diff suppressed because it is too large
Load Diff
858
src/core/monitor-kms.c
Normal file
858
src/core/monitor-kms.c
Normal file
@@ -0,0 +1,858 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include <meta/main.h>
|
||||
#include <meta/errors.h>
|
||||
#include "monitor-private.h"
|
||||
#include "edid.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
typedef struct {
|
||||
drmModeConnector *connector;
|
||||
|
||||
unsigned n_encoders;
|
||||
drmModeEncoderPtr *encoders;
|
||||
drmModeEncoderPtr current_encoder;
|
||||
|
||||
/* bitmasks of encoder position in the resources array */
|
||||
uint32_t encoder_mask;
|
||||
uint32_t enc_clone_mask;
|
||||
|
||||
uint32_t dpms_prop_id;
|
||||
uint32_t edid_blob_id;
|
||||
uint32_t has_dpms_prop : 1;
|
||||
uint32_t has_edid_blob : 1;
|
||||
} MetaOutputKms;
|
||||
|
||||
struct _MetaMonitorManagerKms
|
||||
{
|
||||
MetaMonitorManager parent_instance;
|
||||
|
||||
int fd;
|
||||
|
||||
drmModeConnector **connectors;
|
||||
unsigned int n_connectors;
|
||||
|
||||
drmModeEncoder **encoders;
|
||||
unsigned int n_encoders;
|
||||
|
||||
drmModeEncoder *current_encoder;
|
||||
};
|
||||
|
||||
struct _MetaMonitorManagerKmsClass
|
||||
{
|
||||
MetaMonitorManagerClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
|
||||
|
||||
static int
|
||||
compare_outputs (const void *one,
|
||||
const void *two)
|
||||
{
|
||||
const MetaOutput *o_one = one, *o_two = two;
|
||||
|
||||
return strcmp (o_one->name, o_two->name);
|
||||
}
|
||||
|
||||
static char *
|
||||
make_output_name (drmModeConnector *connector)
|
||||
{
|
||||
static const char * const connector_type_names[] = {
|
||||
"unknown", "VGA", "DVII", "DVID", "DVID", "Composite",
|
||||
"SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort",
|
||||
"HDMIA", "HDMIB", "TV", "eDP"
|
||||
};
|
||||
const char *connector_type_name;
|
||||
|
||||
if (connector->connector_type >= 0 &&
|
||||
connector->connector_type < G_N_ELEMENTS (connector_type_names))
|
||||
connector_type_name = connector_type_names[connector->connector_type];
|
||||
else
|
||||
connector_type_name = "unknown";
|
||||
|
||||
return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_output_destroy_notify (MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms;
|
||||
unsigned i;
|
||||
|
||||
output_kms = output->driver_private;
|
||||
|
||||
for (i = 0; i < output_kms->n_encoders; i++)
|
||||
drmModeFreeEncoder (output_kms->encoders[i]);
|
||||
|
||||
g_slice_free (MetaOutputKms, output_kms);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_mode_destroy_notify (MetaMonitorMode *output)
|
||||
{
|
||||
g_slice_free (drmModeModeInfo, output->driver_private);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drm_mode_equal (gconstpointer one,
|
||||
gconstpointer two)
|
||||
{
|
||||
return memcmp (one, two, sizeof (drmModeModeInfo)) == 0;
|
||||
}
|
||||
|
||||
static guint
|
||||
drm_mode_hash (gconstpointer ptr)
|
||||
{
|
||||
const drmModeModeInfo *mode = ptr;
|
||||
guint hash = 0;
|
||||
|
||||
hash ^= mode->clock;
|
||||
hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end;
|
||||
hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end;
|
||||
hash ^= mode->vrefresh;
|
||||
hash ^= mode->flags ^ mode->type;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
find_properties (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutputKms *output_kms)
|
||||
{
|
||||
drmModePropertyPtr prop;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < output_kms->connector->count_props; i++)
|
||||
{
|
||||
prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
|
||||
strcmp(prop->name, "DPMS") == 0)
|
||||
{
|
||||
output_kms->dpms_prop_id = prop->prop_id;
|
||||
output_kms->has_dpms_prop = TRUE;
|
||||
drmModeFreeProperty(prop);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
||||
strcmp (prop->name, "EDID") == 0)
|
||||
{
|
||||
output_kms->edid_blob_id = output_kms->connector->prop_values[i];
|
||||
output_kms->has_edid_blob = TRUE;
|
||||
drmModeFreeProperty(prop);
|
||||
break;
|
||||
}
|
||||
|
||||
drmModeFreeProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_output_edid (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
drmModePropertyBlobPtr edid_blob = NULL;
|
||||
|
||||
if (!output_kms->has_edid_blob)
|
||||
return NULL;
|
||||
|
||||
edid_blob = drmModeGetPropertyBlob (manager_kms->fd, output_kms->edid_blob_id);
|
||||
if (!edid_blob)
|
||||
{
|
||||
meta_warning ("Failed to read EDID of output %s: %s\n", output->name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (edid_blob->length > 0 && edid_blob->length % 128 == 0)
|
||||
return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length,
|
||||
(GDestroyNotify)drmModeFreePropertyBlob, edid_blob);
|
||||
else
|
||||
drmModeFreePropertyBlob (edid_blob);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
drmModeRes *resources;
|
||||
GHashTable *modes;
|
||||
GHashTableIter iter;
|
||||
drmModeModeInfo *mode;
|
||||
unsigned int i, j, k;
|
||||
unsigned int n_actual_outputs;
|
||||
int width, height;
|
||||
|
||||
resources = drmModeGetResources(manager_kms->fd);
|
||||
modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
|
||||
|
||||
manager->max_screen_width = resources->max_width;
|
||||
manager->max_screen_height = resources->max_height;
|
||||
|
||||
manager->power_save_mode = META_POWER_SAVE_ON;
|
||||
|
||||
manager_kms->n_connectors = resources->count_connectors;
|
||||
manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
|
||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||
{
|
||||
drmModeConnector *connector;
|
||||
|
||||
connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]);
|
||||
manager_kms->connectors[i] = connector;
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED)
|
||||
{
|
||||
/* Collect all modes for this connector */
|
||||
for (j = 0; j < (unsigned)connector->count_modes; j++)
|
||||
g_hash_table_add (modes, &connector->modes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
manager_kms->n_encoders = resources->count_encoders;
|
||||
manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders);
|
||||
for (i = 0; i < manager_kms->n_encoders; i++)
|
||||
{
|
||||
manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd,
|
||||
resources->encoders[i]);
|
||||
}
|
||||
|
||||
manager->n_modes = g_hash_table_size (modes);
|
||||
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
|
||||
g_hash_table_iter_init (&iter, modes);
|
||||
i = 0;
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode))
|
||||
{
|
||||
MetaMonitorMode *meta_mode;
|
||||
|
||||
meta_mode = &manager->modes[i];
|
||||
|
||||
meta_mode->mode_id = i;
|
||||
meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN);
|
||||
meta_mode->width = mode->hdisplay;
|
||||
meta_mode->height = mode->vdisplay;
|
||||
meta_mode->refresh_rate = (1000 * mode->clock /
|
||||
((float)mode->htotal * mode->vtotal));
|
||||
|
||||
meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
|
||||
meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
|
||||
|
||||
i++;
|
||||
}
|
||||
g_hash_table_destroy (modes);
|
||||
|
||||
manager->n_crtcs = resources->count_crtcs;
|
||||
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
|
||||
width = 0; height = 0;
|
||||
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
|
||||
{
|
||||
drmModeCrtc *crtc;
|
||||
MetaCRTC *meta_crtc;
|
||||
|
||||
crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
|
||||
|
||||
meta_crtc = &manager->crtcs[i];
|
||||
|
||||
meta_crtc->crtc_id = crtc->crtc_id;
|
||||
meta_crtc->rect.x = crtc->x;
|
||||
meta_crtc->rect.y = crtc->y;
|
||||
meta_crtc->rect.width = crtc->width;
|
||||
meta_crtc->rect.height = crtc->height;
|
||||
meta_crtc->is_dirty = FALSE;
|
||||
meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
/* FIXME: implement! */
|
||||
meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
|
||||
if (crtc->mode_valid)
|
||||
{
|
||||
for (j = 0; j < manager->n_modes; j++)
|
||||
{
|
||||
if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private))
|
||||
{
|
||||
meta_crtc->current_mode = &manager->modes[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width);
|
||||
height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
|
||||
}
|
||||
|
||||
drmModeFreeCrtc (crtc);
|
||||
}
|
||||
|
||||
manager->screen_width = width;
|
||||
manager->screen_height = height;
|
||||
|
||||
manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
|
||||
n_actual_outputs = 0;
|
||||
|
||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
drmModeConnector *connector;
|
||||
GArray *crtcs;
|
||||
unsigned int crtc_mask;
|
||||
GBytes *edid;
|
||||
|
||||
connector = manager_kms->connectors[i];
|
||||
meta_output = &manager->outputs[n_actual_outputs];
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED)
|
||||
{
|
||||
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->name = make_output_name (connector);
|
||||
meta_output->width_mm = connector->mmWidth;
|
||||
meta_output->height_mm = connector->mmHeight;
|
||||
|
||||
if (connector->subpixel == DRM_MODE_SUBPIXEL_UNKNOWN)
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
else if (connector->subpixel == DRM_MODE_SUBPIXEL_NONE)
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
|
||||
else
|
||||
meta_output->subpixel_order = connector->subpixel;
|
||||
|
||||
meta_output->n_modes = connector->count_modes;
|
||||
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
|
||||
for (j = 0; j < meta_output->n_modes; j++)
|
||||
{
|
||||
for (k = 0; k < manager->n_modes; k++)
|
||||
{
|
||||
if (drm_mode_equal (&connector->modes[j], manager->modes[k].driver_private))
|
||||
{
|
||||
meta_output->modes[j] = &manager->modes[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
meta_output->preferred_mode = meta_output->modes[0];
|
||||
|
||||
output_kms->connector = connector;
|
||||
output_kms->n_encoders = connector->count_encoders;
|
||||
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
||||
|
||||
crtc_mask = 0x7F;
|
||||
for (j = 0; j < output_kms->n_encoders; j++)
|
||||
{
|
||||
output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]);
|
||||
|
||||
crtc_mask &= output_kms->encoders[j]->possible_crtcs;
|
||||
|
||||
if (output_kms->encoders[j]->encoder_id == connector->encoder_id)
|
||||
output_kms->current_encoder = output_kms->encoders[j];
|
||||
}
|
||||
|
||||
crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
|
||||
|
||||
for (j = 0; j < manager->n_crtcs; j++)
|
||||
{
|
||||
if (crtc_mask & (1 << j))
|
||||
{
|
||||
MetaCRTC *crtc = &manager->crtcs[j];
|
||||
g_array_append_val (crtcs, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
meta_output->n_possible_crtcs = crtcs->len;
|
||||
meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
||||
|
||||
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
||||
{
|
||||
for (j = 0; j < manager->n_crtcs; j++)
|
||||
{
|
||||
if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id)
|
||||
{
|
||||
meta_output->crtc = &manager->crtcs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
meta_output->crtc = NULL;
|
||||
|
||||
meta_output->is_primary = FALSE;
|
||||
meta_output->is_presentation = FALSE;
|
||||
|
||||
find_properties (manager_kms, output_kms);
|
||||
|
||||
edid = read_output_edid (manager_kms, meta_output);
|
||||
if (edid)
|
||||
{
|
||||
MonitorInfo *parsed_edid;
|
||||
gsize len;
|
||||
|
||||
parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
|
||||
if (parsed_edid)
|
||||
{
|
||||
meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
|
||||
meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14);
|
||||
meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
|
||||
|
||||
g_free (parsed_edid);
|
||||
}
|
||||
|
||||
g_bytes_unref (edid);
|
||||
}
|
||||
if (!meta_output->vendor)
|
||||
{
|
||||
meta_output->vendor = g_strdup ("unknown");
|
||||
meta_output->product = g_strdup ("unknown");
|
||||
meta_output->serial = g_strdup ("unknown");
|
||||
}
|
||||
|
||||
/* FIXME: backlight is a very driver specific thing unfortunately,
|
||||
every DDX does its own thing, and the dumb KMS API does not include it.
|
||||
|
||||
For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
|
||||
(one for each major HW maker, and then some).
|
||||
We can't do the same because we're not root.
|
||||
It might be best to leave backlight out of the story and rely on the setuid
|
||||
helper in gnome-settings-daemon.
|
||||
*/
|
||||
meta_output->backlight_min = 0;
|
||||
meta_output->backlight_max = 0;
|
||||
meta_output->backlight = -1;
|
||||
|
||||
n_actual_outputs++;
|
||||
}
|
||||
}
|
||||
|
||||
manager->n_outputs = n_actual_outputs;
|
||||
manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
|
||||
|
||||
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
||||
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
|
||||
|
||||
/* Now fix the clones.
|
||||
Code mostly inspired by xf86-video-modesetting. */
|
||||
|
||||
/* XXX: intel hardware doesn't usually have clones, but we only have intel
|
||||
cards, so this code was never tested! */
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
|
||||
meta_output = &manager->outputs[i];
|
||||
output_kms = meta_output->driver_private;
|
||||
|
||||
output_kms->enc_clone_mask = 0xff;
|
||||
output_kms->encoder_mask = 0;
|
||||
|
||||
for (j = 0; j < output_kms->n_encoders; j++)
|
||||
{
|
||||
for (k = 0; k < manager_kms->n_encoders; k++)
|
||||
{
|
||||
if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id)
|
||||
{
|
||||
output_kms->encoder_mask |= (1 << k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
|
||||
meta_output = &manager->outputs[i];
|
||||
output_kms = meta_output->driver_private;
|
||||
|
||||
if (output_kms->enc_clone_mask == 0)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < manager->n_outputs; j++)
|
||||
{
|
||||
MetaOutput *meta_clone;
|
||||
MetaOutputKms *clone_kms;
|
||||
|
||||
meta_clone = &manager->outputs[i];
|
||||
clone_kms = meta_clone->driver_private;
|
||||
|
||||
if (meta_clone == meta_output)
|
||||
continue;
|
||||
|
||||
if (clone_kms->encoder_mask == 0)
|
||||
continue;
|
||||
|
||||
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
|
||||
{
|
||||
meta_output->n_possible_clones++;
|
||||
meta_output->possible_clones = g_renew (MetaOutput *,
|
||||
meta_output->possible_clones,
|
||||
meta_output->n_possible_clones);
|
||||
meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drmModeFreeResources (resources);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
|
||||
return read_output_edid (manager_kms, output);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
MetaPowerSave mode)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
uint64_t state;
|
||||
unsigned i;
|
||||
|
||||
switch (mode) {
|
||||
case META_POWER_SAVE_ON:
|
||||
state = DRM_MODE_DPMS_ON;
|
||||
break;
|
||||
case META_POWER_SAVE_STANDBY:
|
||||
state = DRM_MODE_DPMS_STANDBY;
|
||||
break;
|
||||
case META_POWER_SAVE_SUSPEND:
|
||||
state = DRM_MODE_DPMS_SUSPEND;
|
||||
break;
|
||||
case META_POWER_SAVE_OFF:
|
||||
state = DRM_MODE_DPMS_SUSPEND;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
|
||||
meta_output = &manager->outputs[i];
|
||||
output_kms = meta_output->driver_private;
|
||||
|
||||
if (output_kms->has_dpms_prop)
|
||||
{
|
||||
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id,
|
||||
output_kms->dpms_prop_id, state);
|
||||
|
||||
if (ok < 0)
|
||||
meta_warning ("Failed to set power save mode for output %s: %s\n",
|
||||
meta_output->name, strerror (errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
crtc_free (CoglKmsCrtc *crtc)
|
||||
{
|
||||
g_free (crtc->connectors);
|
||||
g_slice_free (CoglKmsCrtc, crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
|
||||
MetaCRTCInfo **crtcs,
|
||||
unsigned int n_crtcs,
|
||||
MetaOutputInfo **outputs,
|
||||
unsigned int n_outputs)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
unsigned i;
|
||||
GPtrArray *cogl_crtcs;
|
||||
int screen_width, screen_height;
|
||||
gboolean ok;
|
||||
GError *error;
|
||||
|
||||
cogl_crtcs = g_ptr_array_new_full (manager->n_crtcs, (GDestroyNotify)crtc_free);
|
||||
screen_width = 0; screen_height = 0;
|
||||
for (i = 0; i < n_crtcs; i++)
|
||||
{
|
||||
MetaCRTCInfo *crtc_info = crtcs[i];
|
||||
MetaCRTC *crtc = crtc_info->crtc;
|
||||
CoglKmsCrtc *cogl_crtc;
|
||||
|
||||
crtc->is_dirty = TRUE;
|
||||
|
||||
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
|
||||
g_ptr_array_add (cogl_crtcs, cogl_crtc);
|
||||
|
||||
if (crtc_info->mode == NULL)
|
||||
{
|
||||
cogl_crtc->id = crtc->crtc_id;
|
||||
cogl_crtc->x = 0;
|
||||
cogl_crtc->y = 0;
|
||||
cogl_crtc->count = 0;
|
||||
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
|
||||
cogl_crtc->connectors = NULL;
|
||||
cogl_crtc->count = 0;
|
||||
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaMonitorMode *mode;
|
||||
uint32_t *outputs;
|
||||
unsigned int j, n_outputs;
|
||||
int width, height;
|
||||
|
||||
mode = crtc_info->mode;
|
||||
|
||||
cogl_crtc->id = crtc->crtc_id;
|
||||
cogl_crtc->x = crtc_info->x;
|
||||
cogl_crtc->y = crtc_info->y;
|
||||
cogl_crtc->count = n_outputs = crtc_info->outputs->len;
|
||||
cogl_crtc->connectors = outputs = g_new (uint32_t, n_outputs);
|
||||
|
||||
for (j = 0; j < n_outputs; j++)
|
||||
{
|
||||
MetaOutput *output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
|
||||
|
||||
outputs[j] = output->output_id;
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
}
|
||||
|
||||
memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private,
|
||||
sizeof (drmModeModeInfo));
|
||||
|
||||
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
||||
{
|
||||
width = mode->height;
|
||||
height = mode->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = mode->width;
|
||||
height = mode->height;
|
||||
}
|
||||
|
||||
screen_width = MAX (screen_width, crtc_info->x + width);
|
||||
screen_height = MAX (screen_height, crtc_info->y + height);
|
||||
|
||||
crtc->rect.x = crtc_info->x;
|
||||
crtc->rect.y = crtc_info->y;
|
||||
crtc->rect.width = width;
|
||||
crtc->rect.height = height;
|
||||
crtc->current_mode = mode;
|
||||
crtc->transform = crtc_info->transform;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable CRTCs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_crtcs; i++)
|
||||
{
|
||||
MetaCRTC *crtc = &manager->crtcs[i];
|
||||
CoglKmsCrtc *cogl_crtc;
|
||||
|
||||
crtc->logical_monitor = NULL;
|
||||
|
||||
if (crtc->is_dirty)
|
||||
{
|
||||
crtc->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
|
||||
g_ptr_array_add (cogl_crtcs, cogl_crtc);
|
||||
|
||||
cogl_crtc->id = crtc->crtc_id;
|
||||
cogl_crtc->x = 0;
|
||||
cogl_crtc->y = 0;
|
||||
cogl_crtc->count = 0;
|
||||
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
|
||||
cogl_crtc->connectors = NULL;
|
||||
cogl_crtc->count = 0;
|
||||
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
|
||||
error = NULL;
|
||||
ok = cogl_kms_display_set_layout (cogl_display, screen_width, screen_height,
|
||||
(CoglKmsCrtc**)cogl_crtcs->pdata, cogl_crtcs->len, &error);
|
||||
g_ptr_array_unref (cogl_crtcs);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
meta_warning ("Applying display configuration failed: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutputInfo *output_info = outputs[i];
|
||||
MetaOutput *output = output_info->output;
|
||||
|
||||
output->is_primary = output_info->is_primary;
|
||||
output->is_presentation = output_info->is_presentation;
|
||||
}
|
||||
|
||||
/* Disable outputs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *output = &manager->outputs[i];
|
||||
|
||||
if (output->is_dirty)
|
||||
{
|
||||
output->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
output->crtc = NULL;
|
||||
output->is_primary = FALSE;
|
||||
}
|
||||
|
||||
manager->screen_width = screen_width;
|
||||
manager->screen_height = screen_height;
|
||||
|
||||
meta_monitor_manager_rebuild_derived (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager,
|
||||
MetaCRTC *crtc,
|
||||
gsize *size,
|
||||
unsigned short **red,
|
||||
unsigned short **green,
|
||||
unsigned short **blue)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
drmModeCrtc *kms_crtc;
|
||||
|
||||
kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id);
|
||||
|
||||
*size = kms_crtc->gamma_size;
|
||||
*red = g_new (unsigned short, *size);
|
||||
*green = g_new (unsigned short, *size);
|
||||
*blue = g_new (unsigned short, *size);
|
||||
|
||||
drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue);
|
||||
|
||||
drmModeFreeCrtc (kms_crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
|
||||
MetaCRTC *crtc,
|
||||
gsize size,
|
||||
unsigned short *red,
|
||||
unsigned short *green,
|
||||
unsigned short *blue)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
|
||||
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
CoglRenderer *cogl_renderer;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_renderer = cogl_display_get_renderer (cogl_display);
|
||||
|
||||
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_finalize (GObject *object)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < manager_kms->n_encoders; i++)
|
||||
drmModeFreeEncoder (manager_kms->encoders[i]);
|
||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||
drmModeFreeConnector (manager_kms->connectors[i]);
|
||||
|
||||
g_free (manager_kms->encoders);
|
||||
g_free (manager_kms->connectors);
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
|
||||
{
|
||||
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_monitor_manager_kms_finalize;
|
||||
|
||||
manager_class->read_current = meta_monitor_manager_kms_read_current;
|
||||
manager_class->read_edid = meta_monitor_manager_kms_read_edid;
|
||||
manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration;
|
||||
manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode;
|
||||
manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma;
|
||||
manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma;
|
||||
}
|
||||
|
416
src/core/monitor-private.h
Normal file
416
src/core/monitor-private.h
Normal file
@@ -0,0 +1,416 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* \file screen-private.h Handling of monitor configuration
|
||||
*
|
||||
* Managing multiple monitors
|
||||
* This file contains structures and functions that handle
|
||||
* multiple monitors, including reading the current configuration
|
||||
* and available hardware, and applying it.
|
||||
*
|
||||
* This interface is private to mutter, API users should look
|
||||
* at MetaScreen instead.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_MONITOR_PRIVATE_H
|
||||
#define META_MONITOR_PRIVATE_H
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <libgnome-desktop/gnome-pnp-ids.h>
|
||||
|
||||
#include "display-private.h"
|
||||
#include <meta/screen.h>
|
||||
#include "stack-tracker.h"
|
||||
#include "ui.h"
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include <wayland-server.h>
|
||||
#endif
|
||||
#include "meta-xrandr-shared.h"
|
||||
|
||||
#include "meta-dbus-xrandr.h"
|
||||
|
||||
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
|
||||
typedef struct _MetaMonitorManager MetaMonitorManager;
|
||||
typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass;
|
||||
typedef struct _MetaMonitorConfig MetaMonitorConfig;
|
||||
|
||||
#ifndef HAVE_WAYLAND
|
||||
enum wl_output_transform {
|
||||
WL_OUTPUT_TRANSFORM_NORMAL,
|
||||
WL_OUTPUT_TRANSFORM_90,
|
||||
WL_OUTPUT_TRANSFORM_180,
|
||||
WL_OUTPUT_TRANSFORM_270,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_90,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_180,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_270
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct _MetaOutput MetaOutput;
|
||||
typedef struct _MetaCRTC MetaCRTC;
|
||||
typedef struct _MetaMonitorMode MetaMonitorMode;
|
||||
typedef struct _MetaMonitorInfo MetaMonitorInfo;
|
||||
typedef struct _MetaCRTCInfo MetaCRTCInfo;
|
||||
typedef struct _MetaOutputInfo MetaOutputInfo;
|
||||
|
||||
struct _MetaOutput
|
||||
{
|
||||
/* The CRTC driving this output, NULL if the output is not enabled */
|
||||
MetaCRTC *crtc;
|
||||
/* The low-level ID of this output, used to apply back configuration */
|
||||
glong output_id;
|
||||
char *name;
|
||||
char *vendor;
|
||||
char *product;
|
||||
char *serial;
|
||||
int width_mm;
|
||||
int height_mm;
|
||||
CoglSubpixelOrder subpixel_order;
|
||||
|
||||
MetaMonitorMode *preferred_mode;
|
||||
MetaMonitorMode **modes;
|
||||
unsigned int n_modes;
|
||||
|
||||
MetaCRTC **possible_crtcs;
|
||||
unsigned int n_possible_crtcs;
|
||||
|
||||
MetaOutput **possible_clones;
|
||||
unsigned int n_possible_clones;
|
||||
|
||||
int backlight;
|
||||
int backlight_min;
|
||||
int backlight_max;
|
||||
|
||||
/* Used when changing configuration */
|
||||
gboolean is_dirty;
|
||||
|
||||
/* The low-level bits used to build the high-level info
|
||||
in MetaMonitorInfo
|
||||
|
||||
XXX: flags maybe?
|
||||
There is a lot of code that uses MonitorInfo->is_primary,
|
||||
but nobody uses MetaOutput yet
|
||||
*/
|
||||
gboolean is_primary;
|
||||
gboolean is_presentation;
|
||||
|
||||
gpointer driver_private;
|
||||
GDestroyNotify driver_notify;
|
||||
};
|
||||
|
||||
struct _MetaCRTC
|
||||
{
|
||||
glong crtc_id;
|
||||
MetaRectangle rect;
|
||||
MetaMonitorMode *current_mode;
|
||||
enum wl_output_transform transform;
|
||||
unsigned int all_transforms;
|
||||
|
||||
/* Only used to build the logical configuration
|
||||
from the HW one
|
||||
*/
|
||||
MetaMonitorInfo *logical_monitor;
|
||||
|
||||
/* Used when changing configuration */
|
||||
gboolean is_dirty;
|
||||
};
|
||||
|
||||
struct _MetaMonitorMode
|
||||
{
|
||||
/* The low-level ID of this mode, used to apply back configuration */
|
||||
glong mode_id;
|
||||
char *name;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
float refresh_rate;
|
||||
|
||||
gpointer driver_private;
|
||||
GDestroyNotify driver_notify;
|
||||
};
|
||||
|
||||
/**
|
||||
* MetaMonitorInfo:
|
||||
*
|
||||
* A structure with high-level information about monitors.
|
||||
* This corresponds to a subset of the compositor coordinate space.
|
||||
* Clones are only reported once, irrespective of the way
|
||||
* they're implemented (two CRTCs configured for the same
|
||||
* coordinates or one CRTCs driving two outputs). Inactive CRTCs
|
||||
* are ignored, and so are disabled outputs.
|
||||
*/
|
||||
struct _MetaMonitorInfo
|
||||
{
|
||||
int number;
|
||||
int xinerama_index;
|
||||
MetaRectangle rect;
|
||||
gboolean is_primary;
|
||||
gboolean is_presentation; /* XXX: not yet used */
|
||||
gboolean in_fullscreen;
|
||||
|
||||
/* The primary or first output for this monitor, 0 if we can't figure out.
|
||||
It can be matched to an output_id of a MetaOutput.
|
||||
|
||||
This is used as an opaque token on reconfiguration when switching from
|
||||
clone to extened, to decide on what output the windows should go next
|
||||
(it's an attempt to keep windows on the same monitor, and preferably on
|
||||
the primary one).
|
||||
*/
|
||||
glong output_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* MetaCRTCInfo:
|
||||
* This represents the writable part of a CRTC, as deserialized from DBus
|
||||
* or built by MetaMonitorConfig
|
||||
*
|
||||
* Note: differently from the other structures in this file, MetaCRTCInfo
|
||||
* is handled by pointer. This is to accomodate the usage in MetaMonitorConfig
|
||||
*/
|
||||
struct _MetaCRTCInfo {
|
||||
MetaCRTC *crtc;
|
||||
MetaMonitorMode *mode;
|
||||
int x;
|
||||
int y;
|
||||
enum wl_output_transform transform;
|
||||
GPtrArray *outputs;
|
||||
};
|
||||
|
||||
/*
|
||||
* MetaOutputInfo:
|
||||
* this is the same as MetaOutputInfo, but for CRTCs
|
||||
*/
|
||||
struct _MetaOutputInfo {
|
||||
MetaOutput *output;
|
||||
gboolean is_primary;
|
||||
gboolean is_presentation;
|
||||
};
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ())
|
||||
#define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager))
|
||||
#define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
|
||||
#define META_IS_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER))
|
||||
#define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER))
|
||||
#define META_MONITOR_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
|
||||
|
||||
struct _MetaMonitorManager
|
||||
{
|
||||
MetaDBusDisplayConfigSkeleton parent_instance;
|
||||
|
||||
/* XXX: this structure is very badly
|
||||
packed, but I like the logical organization
|
||||
of fields */
|
||||
|
||||
gboolean in_init;
|
||||
unsigned int serial;
|
||||
|
||||
MetaPowerSave power_save_mode;
|
||||
|
||||
int max_screen_width;
|
||||
int max_screen_height;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
|
||||
/* Outputs refer to physical screens,
|
||||
CRTCs refer to stuff that can drive outputs
|
||||
(like encoders, but less tied to the HW),
|
||||
while monitor_infos refer to logical ones.
|
||||
|
||||
See also the comment in monitor-private.h
|
||||
*/
|
||||
MetaOutput *outputs;
|
||||
unsigned int n_outputs;
|
||||
|
||||
MetaMonitorMode *modes;
|
||||
unsigned int n_modes;
|
||||
|
||||
MetaCRTC *crtcs;
|
||||
unsigned int n_crtcs;
|
||||
|
||||
MetaMonitorInfo *monitor_infos;
|
||||
unsigned int n_monitor_infos;
|
||||
int primary_monitor_index;
|
||||
|
||||
int dbus_name_id;
|
||||
|
||||
int persistent_timeout_id;
|
||||
MetaMonitorConfig *config;
|
||||
|
||||
GnomePnpIds *pnp_ids;
|
||||
};
|
||||
|
||||
struct _MetaMonitorManagerClass
|
||||
{
|
||||
MetaDBusDisplayConfigSkeletonClass parent_class;
|
||||
|
||||
void (*read_current) (MetaMonitorManager *);
|
||||
|
||||
char* (*get_edid_file) (MetaMonitorManager *,
|
||||
MetaOutput *);
|
||||
GBytes* (*read_edid) (MetaMonitorManager *,
|
||||
MetaOutput *);
|
||||
|
||||
void (*apply_configuration) (MetaMonitorManager *,
|
||||
MetaCRTCInfo **,
|
||||
unsigned int ,
|
||||
MetaOutputInfo **,
|
||||
unsigned int);
|
||||
|
||||
void (*set_power_save_mode) (MetaMonitorManager *,
|
||||
MetaPowerSave);
|
||||
|
||||
void (*change_backlight) (MetaMonitorManager *,
|
||||
MetaOutput *,
|
||||
int);
|
||||
|
||||
void (*get_crtc_gamma) (MetaMonitorManager *,
|
||||
MetaCRTC *,
|
||||
gsize *,
|
||||
unsigned short **,
|
||||
unsigned short **,
|
||||
unsigned short **);
|
||||
void (*set_crtc_gamma) (MetaMonitorManager *,
|
||||
MetaCRTC *,
|
||||
gsize ,
|
||||
unsigned short *,
|
||||
unsigned short *,
|
||||
unsigned short *);
|
||||
|
||||
gboolean (*handle_xevent) (MetaMonitorManager *,
|
||||
XEvent *);
|
||||
};
|
||||
|
||||
GType meta_monitor_manager_get_type (void);
|
||||
|
||||
void meta_monitor_manager_initialize (void);
|
||||
MetaMonitorManager *meta_monitor_manager_get (void);
|
||||
|
||||
void meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager);
|
||||
|
||||
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
|
||||
unsigned int *n_infos);
|
||||
|
||||
MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
|
||||
unsigned int *n_outputs);
|
||||
|
||||
void meta_monitor_manager_get_resources (MetaMonitorManager *manager,
|
||||
MetaMonitorMode **modes,
|
||||
unsigned int *n_modes,
|
||||
MetaCRTC **crtcs,
|
||||
unsigned int *n_crtcs,
|
||||
MetaOutput **outputs,
|
||||
unsigned int *n_outputs);
|
||||
|
||||
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
|
||||
|
||||
gboolean meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
|
||||
XEvent *event);
|
||||
|
||||
void meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
void meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
void meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
|
||||
MetaCRTCInfo **crtcs,
|
||||
unsigned int n_crtcs,
|
||||
MetaOutputInfo **outputs,
|
||||
unsigned int n_outputs);
|
||||
|
||||
void meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
|
||||
gboolean ok);
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ())
|
||||
#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr))
|
||||
#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
|
||||
#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR))
|
||||
#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR))
|
||||
#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
|
||||
|
||||
typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass;
|
||||
typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
|
||||
|
||||
GType meta_monitor_manager_xrandr_get_type (void);
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ())
|
||||
#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms))
|
||||
#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
|
||||
#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS))
|
||||
#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS))
|
||||
#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
|
||||
|
||||
typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass;
|
||||
typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms;
|
||||
|
||||
GType meta_monitor_manager_kms_get_type (void);
|
||||
|
||||
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
|
||||
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
|
||||
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||
#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
|
||||
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG))
|
||||
#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||
|
||||
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MetaMonitorConfig *meta_monitor_config_new (void);
|
||||
|
||||
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_monitor_config_make_default (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_monitor_config_update_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
|
||||
|
||||
void meta_monitor_config_restore_previous (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_crtc_info_free (MetaCRTCInfo *info);
|
||||
void meta_output_info_free (MetaOutputInfo *info);
|
||||
|
||||
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
||||
int n_old_outputs);
|
||||
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
|
||||
int n_old_modes);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return (transform % 2);
|
||||
}
|
||||
|
||||
#endif
|
1086
src/core/monitor-xrandr.c
Normal file
1086
src/core/monitor-xrandr.c
Normal file
File diff suppressed because it is too large
Load Diff
1428
src/core/monitor.c
Normal file
1428
src/core/monitor.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -46,8 +46,15 @@ print_version (const gchar *option_name,
|
||||
}
|
||||
|
||||
static gchar *plugin = "default";
|
||||
static gboolean opt_nested = FALSE;
|
||||
|
||||
GOptionEntry mutter_options[] = {
|
||||
{
|
||||
"nested", 0, 0, G_OPTION_ARG_NONE,
|
||||
&opt_nested,
|
||||
N_("Run nested as an application for testing"),
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
"version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
print_version,
|
||||
@@ -77,6 +84,8 @@ main (int argc, char **argv)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
meta_set_is_wayland_compositor (opt_nested);
|
||||
|
||||
if (plugin)
|
||||
meta_plugin_manager_load (plugin);
|
||||
|
||||
|
277
src/core/prefs.c
277
src/core/prefs.c
@@ -55,6 +55,7 @@
|
||||
#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_OVERLAY_KEY "overlay-key"
|
||||
#define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
|
||||
@@ -65,6 +66,7 @@
|
||||
#define SCHEMA_GENERAL "org.gnome.desktop.wm.preferences"
|
||||
#define SCHEMA_MUTTER "org.gnome.mutter"
|
||||
#define SCHEMA_INTERFACE "org.gnome.desktop.interface"
|
||||
#define SCHEMA_INPUT_SOURCES "org.gnome.desktop.input-sources"
|
||||
|
||||
#define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
|
||||
|
||||
@@ -87,7 +89,6 @@ static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_
|
||||
static GDesktopTitlebarAction action_middle_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_LOWER;
|
||||
static GDesktopTitlebarAction action_right_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_MENU;
|
||||
static gboolean dynamic_workspaces = FALSE;
|
||||
static gboolean application_based = FALSE;
|
||||
static gboolean disable_workarounds = FALSE;
|
||||
static gboolean auto_raise = FALSE;
|
||||
static gboolean auto_raise_delay = 500;
|
||||
@@ -115,6 +116,7 @@ static gboolean workspaces_only_on_primary = FALSE;
|
||||
|
||||
static gboolean no_tab_popup = FALSE;
|
||||
|
||||
static char *iso_next_group_option = NULL;
|
||||
|
||||
static void handle_preference_update_enum (GSettings *settings,
|
||||
gchar *key);
|
||||
@@ -122,7 +124,6 @@ static gboolean update_binding (MetaKeyPref *binding,
|
||||
gchar **strokes);
|
||||
static gboolean update_key_binding (const char *key,
|
||||
gchar **strokes);
|
||||
static gboolean update_workspace_names (void);
|
||||
|
||||
static void settings_changed (GSettings *settings,
|
||||
gchar *key,
|
||||
@@ -140,11 +141,11 @@ static gboolean theme_name_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean overlay_key_handler (GVariant*, gpointer*, gpointer);
|
||||
static gboolean iso_next_group_handler (GVariant*, gpointer*, gpointer);
|
||||
|
||||
static void do_override (char *key, char *schema);
|
||||
|
||||
static void init_bindings (void);
|
||||
static void init_workspace_names (void);
|
||||
|
||||
|
||||
typedef struct
|
||||
@@ -198,6 +199,13 @@ typedef struct
|
||||
gchar **target;
|
||||
} MetaStringPreference;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaBasePreference base;
|
||||
GSettingsGetMapping handler;
|
||||
gchar ***target;
|
||||
} MetaStringArrayPreference;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaBasePreference base;
|
||||
@@ -289,13 +297,6 @@ static MetaBoolPreference preferences_bool[] =
|
||||
},
|
||||
&dynamic_workspaces,
|
||||
},
|
||||
{
|
||||
{ "application-based",
|
||||
SCHEMA_GENERAL,
|
||||
META_PREF_APPLICATION_BASED,
|
||||
},
|
||||
NULL, /* feature is known but disabled */
|
||||
},
|
||||
{
|
||||
{ "disable-workarounds",
|
||||
SCHEMA_GENERAL,
|
||||
@@ -436,6 +437,27 @@ static MetaStringPreference preferences_string[] =
|
||||
{ { NULL, 0, 0 }, NULL },
|
||||
};
|
||||
|
||||
static MetaStringArrayPreference preferences_string_array[] =
|
||||
{
|
||||
{
|
||||
{ KEY_WORKSPACE_NAMES,
|
||||
SCHEMA_GENERAL,
|
||||
META_PREF_KEYBINDINGS,
|
||||
},
|
||||
NULL,
|
||||
&workspace_names,
|
||||
},
|
||||
{
|
||||
{ KEY_XKB_OPTIONS,
|
||||
SCHEMA_INPUT_SOURCES,
|
||||
META_PREF_KEYBINDINGS,
|
||||
},
|
||||
iso_next_group_handler,
|
||||
NULL,
|
||||
},
|
||||
{ { NULL, 0, 0 }, NULL },
|
||||
};
|
||||
|
||||
static MetaIntPreference preferences_int[] =
|
||||
{
|
||||
{
|
||||
@@ -555,6 +577,42 @@ handle_preference_init_string (void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_preference_init_string_array (void)
|
||||
{
|
||||
MetaStringArrayPreference *cursor = preferences_string_array;
|
||||
|
||||
while (cursor->base.key != NULL)
|
||||
{
|
||||
char **value;
|
||||
|
||||
/* Complex keys have a mapping function to check validity */
|
||||
if (cursor->handler)
|
||||
{
|
||||
if (cursor->target)
|
||||
meta_bug ("%s has both a target and a handler\n", cursor->base.key);
|
||||
|
||||
g_settings_get_mapped (SETTINGS (cursor->base.schema),
|
||||
cursor->base.key, cursor->handler, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cursor->target)
|
||||
meta_bug ("%s must have handler or target\n", cursor->base.key);
|
||||
|
||||
if (*(cursor->target))
|
||||
g_strfreev (*(cursor->target));
|
||||
|
||||
value = g_settings_get_strv (SETTINGS (cursor->base.schema),
|
||||
cursor->base.key);
|
||||
|
||||
*(cursor->target) = value;
|
||||
}
|
||||
|
||||
++cursor;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_preference_init_int (void)
|
||||
{
|
||||
@@ -673,6 +731,56 @@ handle_preference_update_string (GSettings *settings,
|
||||
queue_changed (cursor->base.pref);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_preference_update_string_array (GSettings *settings,
|
||||
gchar *key)
|
||||
{
|
||||
MetaStringArrayPreference *cursor = preferences_string_array;
|
||||
gboolean inform_listeners = FALSE;
|
||||
|
||||
while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
|
||||
++cursor;
|
||||
|
||||
if (cursor->base.key==NULL)
|
||||
/* Didn't recognise that key. */
|
||||
return;
|
||||
|
||||
/* Complex keys have a mapping function to check validity */
|
||||
if (cursor->handler)
|
||||
{
|
||||
if (cursor->target)
|
||||
meta_bug ("%s has both a target and a handler\n", cursor->base.key);
|
||||
|
||||
g_settings_get_mapped (SETTINGS (cursor->base.schema),
|
||||
cursor->base.key, cursor->handler, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
char **values, **previous;
|
||||
int n_values, n_previous, i;
|
||||
|
||||
if (!cursor->target)
|
||||
meta_bug ("%s must have handler or target\n", cursor->base.key);
|
||||
|
||||
values = g_settings_get_strv (SETTINGS (cursor->base.schema),
|
||||
cursor->base.key);
|
||||
n_values = g_strv_length (values);
|
||||
previous = *(cursor->target);
|
||||
n_previous = previous ? g_strv_length (previous) : 0;
|
||||
|
||||
inform_listeners = n_previous != n_values;
|
||||
for (i = 0; i < n_values && !inform_listeners; i++)
|
||||
inform_listeners = g_strcmp0 (values[i], previous[i]) != 0;
|
||||
|
||||
if (*(cursor->target))
|
||||
g_strfreev (*(cursor->target));
|
||||
*(cursor->target) = values;
|
||||
}
|
||||
|
||||
if (inform_listeners)
|
||||
queue_changed (cursor->base.pref);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_preference_update_int (GSettings *settings,
|
||||
gchar *key)
|
||||
@@ -857,6 +965,11 @@ meta_prefs_init (void)
|
||||
G_CALLBACK (settings_changed), NULL);
|
||||
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
|
||||
|
||||
settings = g_settings_new (SCHEMA_INPUT_SOURCES);
|
||||
g_signal_connect (settings, "changed::" KEY_XKB_OPTIONS,
|
||||
G_CALLBACK (settings_changed), NULL);
|
||||
g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INPUT_SOURCES), settings);
|
||||
|
||||
|
||||
for (tmp = overridden_keys; tmp; tmp = tmp->next)
|
||||
{
|
||||
@@ -869,10 +982,10 @@ meta_prefs_init (void)
|
||||
handle_preference_init_enum ();
|
||||
handle_preference_init_bool ();
|
||||
handle_preference_init_string ();
|
||||
handle_preference_init_string_array ();
|
||||
handle_preference_init_int ();
|
||||
|
||||
init_bindings ();
|
||||
init_workspace_names ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1020,14 +1133,6 @@ settings_changed (GSettings *settings,
|
||||
MetaEnumPreference *cursor;
|
||||
gboolean found_enum;
|
||||
|
||||
/* String array, handled separately */
|
||||
if (strcmp (key, KEY_WORKSPACE_NAMES) == 0)
|
||||
{
|
||||
if (update_workspace_names ())
|
||||
queue_changed (META_PREF_WORKSPACE_NAMES);
|
||||
return;
|
||||
}
|
||||
|
||||
value = g_settings_get_value (settings, key);
|
||||
type = g_variant_get_type (value);
|
||||
|
||||
@@ -1035,6 +1140,8 @@ settings_changed (GSettings *settings,
|
||||
handle_preference_update_bool (settings, key);
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
|
||||
handle_preference_update_int (settings, key);
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING_ARRAY))
|
||||
handle_preference_update_string_array (settings, key);
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
cursor = preferences_enum;
|
||||
@@ -1554,6 +1661,39 @@ overlay_key_handler (GVariant *value,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iso_next_group_handler (GVariant *value,
|
||||
gpointer *result,
|
||||
gpointer data)
|
||||
{
|
||||
const char **xkb_options, **p;
|
||||
const char *option = NULL;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
*result = NULL; /* ignored */
|
||||
xkb_options = g_variant_get_strv (value, NULL);
|
||||
|
||||
for (p = xkb_options; p && *p; ++p)
|
||||
if (g_str_has_prefix (*p, "grp:"))
|
||||
{
|
||||
option = (*p + 4);
|
||||
break;
|
||||
}
|
||||
|
||||
changed = (g_strcmp0 (option, iso_next_group_option) != 0);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
g_free (iso_next_group_option);
|
||||
iso_next_group_option = g_strdup (option);
|
||||
queue_changed (META_PREF_KEYBINDINGS);
|
||||
}
|
||||
|
||||
g_free (xkb_options);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const PangoFontDescription*
|
||||
meta_prefs_get_titlebar_font (void)
|
||||
{
|
||||
@@ -1575,14 +1715,6 @@ meta_prefs_get_dynamic_workspaces (void)
|
||||
return dynamic_workspaces;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_prefs_get_application_based (void)
|
||||
{
|
||||
return FALSE; /* For now, we never want this to do anything */
|
||||
|
||||
return application_based;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_prefs_get_disable_workarounds (void)
|
||||
{
|
||||
@@ -1620,9 +1752,6 @@ meta_preference_to_string (MetaPreference pref)
|
||||
case META_PREF_NUM_WORKSPACES:
|
||||
return "NUM_WORKSPACES";
|
||||
|
||||
case META_PREF_APPLICATION_BASED:
|
||||
return "APPLICATION_BASED";
|
||||
|
||||
case META_PREF_KEYBINDINGS:
|
||||
return "KEYBINDINGS";
|
||||
|
||||
@@ -1748,20 +1877,15 @@ init_bindings (void)
|
||||
g_hash_table_insert (key_bindings, g_strdup ("overlay-key"), pref);
|
||||
}
|
||||
|
||||
static void
|
||||
init_workspace_names (void)
|
||||
{
|
||||
update_workspace_names ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_binding (MetaKeyPref *binding,
|
||||
gchar **strokes)
|
||||
{
|
||||
GSList *old_bindings, *a, *b;
|
||||
gboolean changed;
|
||||
unsigned int keysym;
|
||||
unsigned int keycode;
|
||||
MetaVirtualModifier mods;
|
||||
gboolean changed = FALSE;
|
||||
MetaKeyCombo *combo;
|
||||
int i;
|
||||
|
||||
@@ -1769,13 +1893,9 @@ update_binding (MetaKeyPref *binding,
|
||||
"Binding \"%s\" has new GSettings value\n",
|
||||
binding->name);
|
||||
|
||||
/* Okay, so, we're about to provide a new list of key combos for this
|
||||
* action. Delete any pre-existing list.
|
||||
*/
|
||||
g_slist_foreach (binding->bindings, (GFunc) g_free, NULL);
|
||||
g_slist_free (binding->bindings);
|
||||
old_bindings = binding->bindings;
|
||||
binding->bindings = NULL;
|
||||
|
||||
|
||||
for (i = 0; strokes && strokes[i]; i++)
|
||||
{
|
||||
keysym = 0;
|
||||
@@ -1810,8 +1930,6 @@ update_binding (MetaKeyPref *binding,
|
||||
* Changing the key in response to a modification could lead to cyclic calls. */
|
||||
continue;
|
||||
}
|
||||
|
||||
changed = TRUE;
|
||||
|
||||
combo = g_malloc0 (sizeof (MetaKeyCombo));
|
||||
combo->keysym = keysym;
|
||||
@@ -1826,6 +1944,34 @@ update_binding (MetaKeyPref *binding,
|
||||
|
||||
binding->bindings = g_slist_reverse (binding->bindings);
|
||||
|
||||
a = old_bindings;
|
||||
b = binding->bindings;
|
||||
while (TRUE)
|
||||
{
|
||||
if ((!a && b) || (a && !b))
|
||||
{
|
||||
changed = TRUE;
|
||||
break;
|
||||
}
|
||||
else if (!a && !b)
|
||||
{
|
||||
changed = FALSE;
|
||||
break;
|
||||
}
|
||||
else if (memcmp (a->data, b->data, sizeof (MetaKeyCombo)) != 0)
|
||||
{
|
||||
changed = TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = a->next;
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free_full (old_bindings, g_free);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -1841,41 +1987,6 @@ update_key_binding (const char *key,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_workspace_names (void)
|
||||
{
|
||||
int i;
|
||||
char **names;
|
||||
int n_workspace_names, n_names;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
names = g_settings_get_strv (SETTINGS (SCHEMA_GENERAL), KEY_WORKSPACE_NAMES);
|
||||
n_names = g_strv_length (names);
|
||||
n_workspace_names = workspace_names ? g_strv_length (workspace_names) : 0;
|
||||
|
||||
for (i = 0; i < n_names; i++)
|
||||
if (n_workspace_names < i + 1 || !workspace_names[i] ||
|
||||
g_strcmp0 (names[i], workspace_names[i]) != 0)
|
||||
{
|
||||
changed = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n_workspace_names != n_names)
|
||||
changed = TRUE;
|
||||
|
||||
if (changed)
|
||||
{
|
||||
if (workspace_names)
|
||||
g_strfreev (workspace_names);
|
||||
workspace_names = names;
|
||||
}
|
||||
else
|
||||
g_strfreev (names);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
const char*
|
||||
meta_prefs_get_workspace_name (int i)
|
||||
{
|
||||
@@ -2075,6 +2186,12 @@ meta_prefs_get_overlay_binding (MetaKeyCombo *combo)
|
||||
*combo = overlay_key_combo;
|
||||
}
|
||||
|
||||
const char *
|
||||
meta_prefs_get_iso_next_group_option (void)
|
||||
{
|
||||
return iso_next_group_option;
|
||||
}
|
||||
|
||||
GDesktopTitlebarAction
|
||||
meta_prefs_get_action_double_click_titlebar (void)
|
||||
{
|
||||
|
@@ -38,17 +38,7 @@
|
||||
#include <X11/Xutil.h>
|
||||
#include "stack-tracker.h"
|
||||
#include "ui.h"
|
||||
|
||||
typedef struct _MetaMonitorInfo MetaMonitorInfo;
|
||||
|
||||
struct _MetaMonitorInfo
|
||||
{
|
||||
int number;
|
||||
MetaRectangle rect;
|
||||
gboolean is_primary;
|
||||
gboolean in_fullscreen;
|
||||
XID output; /* The primary or first output for this crtc, None if no xrandr */
|
||||
};
|
||||
#include "monitor-private.h"
|
||||
|
||||
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
|
||||
gpointer user_data);
|
||||
@@ -93,6 +83,7 @@ struct _MetaScreen
|
||||
MetaStack *stack;
|
||||
MetaStackTracker *stack_tracker;
|
||||
|
||||
MetaCursorTracker *cursor_tracker;
|
||||
MetaCursor current_cursor;
|
||||
|
||||
Window flash_window;
|
||||
@@ -100,10 +91,11 @@ struct _MetaScreen
|
||||
Window wm_sn_selection_window;
|
||||
Atom wm_sn_atom;
|
||||
guint32 wm_sn_timestamp;
|
||||
|
||||
|
||||
MetaMonitorInfo *monitor_infos;
|
||||
int primary_monitor_index;
|
||||
int n_monitor_infos;
|
||||
int primary_monitor_index;
|
||||
gboolean has_xinerama_indices;
|
||||
|
||||
/* Cache the current monitor */
|
||||
int last_monitor_index;
|
||||
@@ -187,6 +179,9 @@ MetaWindow* meta_screen_get_mouse_window (MetaScreen *scre
|
||||
MetaWindow *not_this_one);
|
||||
|
||||
const MetaMonitorInfo* meta_screen_get_current_monitor_info (MetaScreen *screen);
|
||||
const MetaMonitorInfo* meta_screen_get_current_monitor_info_for_pos (MetaScreen *screen,
|
||||
int x,
|
||||
int y);
|
||||
const MetaMonitorInfo* meta_screen_get_monitor_for_rect (MetaScreen *screen,
|
||||
MetaRectangle *rect);
|
||||
const MetaMonitorInfo* meta_screen_get_monitor_for_window (MetaScreen *screen,
|
||||
@@ -228,10 +223,6 @@ void meta_screen_calc_workspace_layout (MetaScreen *screen,
|
||||
MetaWorkspaceLayout *layout);
|
||||
void meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout);
|
||||
|
||||
void meta_screen_resize (MetaScreen *screen,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
|
||||
MetaWindow *keep);
|
||||
|
||||
@@ -254,4 +245,14 @@ void meta_screen_workspace_switched (MetaScreen *screen,
|
||||
|
||||
void meta_screen_set_active_workspace_hint (MetaScreen *screen);
|
||||
|
||||
Window meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
|
||||
|
||||
gboolean meta_screen_handle_xevent (MetaScreen *screen,
|
||||
XEvent *xevent);
|
||||
|
||||
int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
|
||||
int index);
|
||||
int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
|
||||
int index);
|
||||
|
||||
#endif
|
||||
|
@@ -45,13 +45,11 @@
|
||||
#include <meta/compositor.h>
|
||||
#include "mutter-enum-types.h"
|
||||
#include "core.h"
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
|
||||
#ifdef HAVE_RANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
@@ -76,6 +74,9 @@ static void meta_screen_sn_event (SnMonitorEvent *event,
|
||||
void *user_data);
|
||||
#endif
|
||||
|
||||
static void on_monitors_changed (MetaMonitorManager *manager,
|
||||
MetaScreen *screen);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_N_WORKSPACES = 1,
|
||||
@@ -350,250 +351,93 @@ set_wm_icon_size_hint (MetaScreen *screen)
|
||||
#undef N_VALS
|
||||
}
|
||||
|
||||
/* The list of monitors reported by the windowing system might include
|
||||
* mirrored monitors with identical bounds. Since mirrored monitors
|
||||
* shouldn't be treated as separate monitors for most purposes, we
|
||||
* filter them out here. (We ignore the possibility of partially
|
||||
* overlapping monitors because they are rare and it's hard to come
|
||||
* up with any sensible interpretation.)
|
||||
*/
|
||||
static void
|
||||
filter_mirrored_monitors (MetaScreen *screen)
|
||||
meta_screen_ensure_xinerama_indices (MetaScreen *screen)
|
||||
{
|
||||
int i, j;
|
||||
XineramaScreenInfo *infos;
|
||||
int n_infos, i, j;
|
||||
|
||||
/* Currently always true and simplifies things */
|
||||
g_assert (screen->primary_monitor_index == 0);
|
||||
if (screen->has_xinerama_indices)
|
||||
return;
|
||||
|
||||
for (i = 1; i < screen->n_monitor_infos; i++)
|
||||
screen->has_xinerama_indices = TRUE;
|
||||
|
||||
if (!XineramaIsActive (screen->display->xdisplay))
|
||||
return;
|
||||
|
||||
infos = XineramaQueryScreens (screen->display->xdisplay, &n_infos);
|
||||
if (n_infos <= 0 || infos == NULL)
|
||||
{
|
||||
/* In case we've filtered previous monitors */
|
||||
screen->monitor_infos[i].number = i;
|
||||
meta_XFree (infos);
|
||||
return;
|
||||
}
|
||||
|
||||
for (j = 0; j < i; j++)
|
||||
for (i = 0; i < screen->n_monitor_infos; ++i)
|
||||
{
|
||||
for (j = 0; j < n_infos; ++j)
|
||||
{
|
||||
if (meta_rectangle_equal (&screen->monitor_infos[i].rect,
|
||||
&screen->monitor_infos[j].rect))
|
||||
{
|
||||
memmove (&screen->monitor_infos[i],
|
||||
&screen->monitor_infos[i + 1],
|
||||
(screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo));
|
||||
screen->n_monitor_infos--;
|
||||
i--;
|
||||
|
||||
continue;
|
||||
}
|
||||
if (screen->monitor_infos[i].rect.x == infos[j].x_org &&
|
||||
screen->monitor_infos[i].rect.y == infos[j].y_org &&
|
||||
screen->monitor_infos[i].rect.width == infos[j].width &&
|
||||
screen->monitor_infos[i].rect.height == infos[j].height)
|
||||
screen->monitor_infos[i].xinerama_index = j;
|
||||
}
|
||||
}
|
||||
|
||||
meta_XFree (infos);
|
||||
}
|
||||
|
||||
#ifdef HAVE_RANDR
|
||||
static MetaMonitorInfo *
|
||||
find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h)
|
||||
int
|
||||
meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
|
||||
int index)
|
||||
{
|
||||
meta_screen_ensure_xinerama_indices (screen);
|
||||
|
||||
return screen->monitor_infos[index].xinerama_index;
|
||||
}
|
||||
|
||||
int
|
||||
meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
|
||||
int index)
|
||||
{
|
||||
MetaMonitorInfo *info;
|
||||
int i;
|
||||
|
||||
meta_screen_ensure_xinerama_indices (screen);
|
||||
|
||||
for (i = 0; i < screen->n_monitor_infos; i++)
|
||||
{
|
||||
info = &screen->monitor_infos[i];
|
||||
if (x == info->rect.x &&
|
||||
y == info->rect.y &&
|
||||
w == info->rect.width &&
|
||||
h == info->rect.height)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
if (screen->monitor_infos[i].xinerama_index == index)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
|
||||
* outputs the "main". This is the one we consider "owning" the windows, so if
|
||||
* the mirroring is changed to a dual monitor setup then the windows are moved to the
|
||||
* crtc that now has that main output. If one of the outputs is the primary that is
|
||||
* always the main, otherwise we just use the first.
|
||||
*/
|
||||
static XID
|
||||
find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc)
|
||||
{
|
||||
XRROutputInfo *output;
|
||||
RROutput primary_output;
|
||||
int i;
|
||||
XID res;
|
||||
|
||||
primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot);
|
||||
|
||||
res = None;
|
||||
for (i = 0; i < crtc->noutput; i++)
|
||||
{
|
||||
output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]);
|
||||
if (output->connection != RR_Disconnected &&
|
||||
(res == None || crtc->outputs[i] == primary_output))
|
||||
res = crtc->outputs[i];
|
||||
XRRFreeOutputInfo (output);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
reload_monitor_infos (MetaScreen *screen)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
GList *tmp;
|
||||
MetaMonitorManager *manager;
|
||||
|
||||
{
|
||||
GList *tmp;
|
||||
tmp = screen->workspaces;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWorkspace *space = tmp->data;
|
||||
|
||||
tmp = screen->workspaces;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaWorkspace *space = tmp->data;
|
||||
meta_workspace_invalidate_work_area (space);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
meta_workspace_invalidate_work_area (space);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
/* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
|
||||
|
||||
display = screen->display;
|
||||
|
||||
/* Any previous screen->monitor_infos is freed by the caller */
|
||||
|
||||
screen->monitor_infos = NULL;
|
||||
screen->n_monitor_infos = 0;
|
||||
screen->last_monitor_index = 0;
|
||||
|
||||
/* Xinerama doesn't have a concept of primary monitor, however XRandR
|
||||
* does. However, the XRandR xinerama compat code always sorts the
|
||||
* primary output first, so we rely on that here. We could use the
|
||||
* native XRandR calls instead of xinerama, but that would be
|
||||
* slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as
|
||||
* that is defined in terms of xinerama monitor indexes.
|
||||
* So, since we don't need anything in xrandr except the primary
|
||||
* we can keep using xinerama and use the first monitor as the
|
||||
* primary.
|
||||
*/
|
||||
screen->primary_monitor_index = 0;
|
||||
|
||||
screen->has_xinerama_indices = FALSE;
|
||||
screen->display->monitor_cache_invalidated = TRUE;
|
||||
|
||||
if (g_getenv ("MUTTER_DEBUG_XINERAMA"))
|
||||
{
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"Pretending a single monitor has two Xinerama screens\n");
|
||||
manager = meta_monitor_manager_get ();
|
||||
|
||||
screen->monitor_infos = g_new0 (MetaMonitorInfo, 2);
|
||||
screen->n_monitor_infos = 2;
|
||||
|
||||
screen->monitor_infos[0].number = 0;
|
||||
screen->monitor_infos[0].rect = screen->rect;
|
||||
screen->monitor_infos[0].rect.width = screen->rect.width / 2;
|
||||
screen->monitor_infos[0].in_fullscreen = -1;
|
||||
|
||||
screen->monitor_infos[1].number = 1;
|
||||
screen->monitor_infos[1].rect = screen->rect;
|
||||
screen->monitor_infos[1].rect.x = screen->rect.width / 2;
|
||||
screen->monitor_infos[1].rect.width = screen->rect.width / 2;
|
||||
screen->monitor_infos[0].in_fullscreen = -1;
|
||||
}
|
||||
|
||||
if (screen->n_monitor_infos == 0 &&
|
||||
XineramaIsActive (display->xdisplay))
|
||||
{
|
||||
XineramaScreenInfo *infos;
|
||||
int n_infos;
|
||||
int i;
|
||||
|
||||
n_infos = 0;
|
||||
infos = XineramaQueryScreens (display->xdisplay, &n_infos);
|
||||
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"Found %d Xinerama screens on display %s\n",
|
||||
n_infos, display->name);
|
||||
|
||||
if (n_infos > 0)
|
||||
{
|
||||
screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos);
|
||||
screen->n_monitor_infos = n_infos;
|
||||
|
||||
i = 0;
|
||||
while (i < n_infos)
|
||||
{
|
||||
screen->monitor_infos[i].number = infos[i].screen_number;
|
||||
screen->monitor_infos[i].rect.x = infos[i].x_org;
|
||||
screen->monitor_infos[i].rect.y = infos[i].y_org;
|
||||
screen->monitor_infos[i].rect.width = infos[i].width;
|
||||
screen->monitor_infos[i].rect.height = infos[i].height;
|
||||
screen->monitor_infos[i].in_fullscreen = -1;
|
||||
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"Monitor %d is %d,%d %d x %d\n",
|
||||
screen->monitor_infos[i].number,
|
||||
screen->monitor_infos[i].rect.x,
|
||||
screen->monitor_infos[i].rect.y,
|
||||
screen->monitor_infos[i].rect.width,
|
||||
screen->monitor_infos[i].rect.height);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
meta_XFree (infos);
|
||||
|
||||
#ifdef HAVE_RANDR
|
||||
{
|
||||
XRRScreenResources *resources;
|
||||
|
||||
resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot);
|
||||
if (resources)
|
||||
{
|
||||
for (i = 0; i < resources->ncrtc; i++)
|
||||
{
|
||||
XRRCrtcInfo *crtc;
|
||||
MetaMonitorInfo *info;
|
||||
|
||||
crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]);
|
||||
info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height);
|
||||
if (info)
|
||||
info->output = find_main_output_for_crtc (screen, resources, crtc);
|
||||
|
||||
XRRFreeCrtcInfo (crtc);
|
||||
}
|
||||
XRRFreeScreenResources (resources);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (screen->n_monitor_infos > 0)
|
||||
{
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"No Xinerama extension or Xinerama inactive on display %s\n",
|
||||
display->name);
|
||||
}
|
||||
|
||||
/* If no Xinerama, fill in the single screen info so
|
||||
* we can use the field unconditionally
|
||||
*/
|
||||
if (screen->n_monitor_infos == 0)
|
||||
{
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"No Xinerama screens, using default screen info\n");
|
||||
|
||||
screen->monitor_infos = g_new0 (MetaMonitorInfo, 1);
|
||||
screen->n_monitor_infos = 1;
|
||||
|
||||
screen->monitor_infos[0].number = 0;
|
||||
screen->monitor_infos[0].rect = screen->rect;
|
||||
screen->monitor_infos[0].in_fullscreen = -1;
|
||||
}
|
||||
|
||||
filter_mirrored_monitors (screen);
|
||||
|
||||
screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE;
|
||||
|
||||
g_assert (screen->n_monitor_infos > 0);
|
||||
g_assert (screen->monitor_infos != NULL);
|
||||
screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager,
|
||||
(unsigned*)&screen->n_monitor_infos);
|
||||
screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
|
||||
}
|
||||
|
||||
/* The guard window allows us to leave minimized windows mapped so
|
||||
@@ -603,12 +447,13 @@ reload_monitor_infos (MetaScreen *screen)
|
||||
* should effectively be forwarded to events on the background actor,
|
||||
* providing that the scene graph is set up correctly.
|
||||
*/
|
||||
static Window
|
||||
create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
Window
|
||||
meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
{
|
||||
XSetWindowAttributes attributes;
|
||||
Window guard_window;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
attributes.event_mask = NoEventMask;
|
||||
attributes.override_redirect = True;
|
||||
@@ -641,12 +486,14 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
XISelectEvents (xdisplay, guard_window, &mask, 1);
|
||||
}
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = guard_window;
|
||||
meta_stack_tracker_record_add (screen->stack_tracker,
|
||||
guard_window,
|
||||
&stack_window,
|
||||
create_serial);
|
||||
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
guard_window,
|
||||
&stack_window,
|
||||
XNextRequest (xdisplay));
|
||||
XLowerWindow (xdisplay, guard_window);
|
||||
XMapWindow (xdisplay, guard_window);
|
||||
@@ -668,6 +515,7 @@ meta_screen_new (MetaDisplay *display,
|
||||
char buf[128];
|
||||
guint32 manager_timestamp;
|
||||
gulong current_workspace;
|
||||
MetaMonitorManager *manager;
|
||||
|
||||
replace_current_wm = meta_get_replace_current_wm ();
|
||||
|
||||
@@ -826,8 +674,18 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->xscreen = ScreenOfDisplay (xdisplay, number);
|
||||
screen->xroot = xroot;
|
||||
screen->rect.x = screen->rect.y = 0;
|
||||
screen->rect.width = WidthOfScreen (screen->xscreen);
|
||||
screen->rect.height = HeightOfScreen (screen->xscreen);
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
meta_monitor_manager_initialize ();
|
||||
|
||||
manager = meta_monitor_manager_get ();
|
||||
g_signal_connect (manager, "monitors-changed",
|
||||
G_CALLBACK (on_monitors_changed), screen);
|
||||
|
||||
meta_monitor_manager_get_screen_size (manager,
|
||||
&screen->rect.width,
|
||||
&screen->rect.height);
|
||||
|
||||
screen->current_cursor = -1; /* invalid/unset */
|
||||
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
|
||||
screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
|
||||
@@ -852,12 +710,9 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->compositor_data = NULL;
|
||||
screen->guard_window = None;
|
||||
|
||||
screen->monitor_infos = NULL;
|
||||
screen->n_monitor_infos = 0;
|
||||
screen->last_monitor_index = 0;
|
||||
|
||||
reload_monitor_infos (screen);
|
||||
|
||||
|
||||
meta_cursor_tracker_get_for_screen (screen);
|
||||
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
|
||||
|
||||
/* Handle creating a no_focus_window for this screen */
|
||||
@@ -941,7 +796,7 @@ meta_screen_new (MetaDisplay *display,
|
||||
|
||||
meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
|
||||
screen->number, screen->screen_name, screen->xroot);
|
||||
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
@@ -1082,8 +937,8 @@ meta_screen_manage_all_windows (MetaScreen *screen)
|
||||
meta_display_grab (screen->display);
|
||||
|
||||
if (screen->guard_window == None)
|
||||
screen->guard_window = create_guard_window (screen->display->xdisplay,
|
||||
screen);
|
||||
screen->guard_window =
|
||||
meta_screen_create_guard_window (screen->display->xdisplay, screen);
|
||||
|
||||
windows = list_windows (screen);
|
||||
|
||||
@@ -1613,29 +1468,18 @@ void
|
||||
meta_screen_set_cursor (MetaScreen *screen,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
Cursor xcursor;
|
||||
|
||||
if (cursor == screen->current_cursor)
|
||||
return;
|
||||
|
||||
screen->current_cursor = cursor;
|
||||
|
||||
xcursor = meta_display_create_x_cursor (screen->display, cursor);
|
||||
XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
|
||||
XFlush (screen->display->xdisplay);
|
||||
XFreeCursor (screen->display->xdisplay, xcursor);
|
||||
meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_update_cursor (MetaScreen *screen)
|
||||
{
|
||||
Cursor xcursor;
|
||||
|
||||
xcursor = meta_display_create_x_cursor (screen->display,
|
||||
screen->current_cursor);
|
||||
XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
|
||||
XFlush (screen->display->xdisplay);
|
||||
XFreeCursor (screen->display->xdisplay, xcursor);
|
||||
meta_cursor_tracker_set_root_cursor (screen->cursor_tracker,
|
||||
screen->current_cursor);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1898,12 +1742,15 @@ meta_screen_tile_preview_update_timeout (gpointer data)
|
||||
{
|
||||
Window xwindow;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
screen->tile_preview = meta_tile_preview_new (screen->number);
|
||||
xwindow = meta_tile_preview_get_xwindow (screen->tile_preview,
|
||||
&create_serial);
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = xwindow;
|
||||
meta_stack_tracker_record_add (screen->stack_tracker,
|
||||
xwindow,
|
||||
&stack_window,
|
||||
create_serial);
|
||||
}
|
||||
|
||||
@@ -2216,6 +2063,65 @@ meta_screen_get_current_monitor_info (MetaScreen *screen)
|
||||
return &screen->monitor_infos[monitor_index];
|
||||
}
|
||||
|
||||
const MetaMonitorInfo*
|
||||
meta_screen_get_current_monitor_info_for_pos (MetaScreen *screen,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
int monitor_index;
|
||||
monitor_index = meta_screen_get_current_monitor_for_pos (screen, x, y);
|
||||
return &screen->monitor_infos[monitor_index];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* meta_screen_get_current_monitor_for_pos:
|
||||
* @screen: a #MetaScreen
|
||||
* @x: The x coordinate
|
||||
* @y: The y coordinate
|
||||
*
|
||||
* Gets the index of the monitor that contains the passed coordinates.
|
||||
*
|
||||
* Return value: a monitor index
|
||||
*/
|
||||
int
|
||||
meta_screen_get_current_monitor_for_pos (MetaScreen *screen,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
if (screen->n_monitor_infos == 1)
|
||||
return 0;
|
||||
else if (screen->display->monitor_cache_invalidated)
|
||||
{
|
||||
int i;
|
||||
MetaRectangle pointer_position;
|
||||
pointer_position.x = x;
|
||||
pointer_position.y = y;
|
||||
pointer_position.width = pointer_position.height = 1;
|
||||
|
||||
screen->display->monitor_cache_invalidated = FALSE;
|
||||
screen->last_monitor_index = 0;
|
||||
|
||||
for (i = 0; i < screen->n_monitor_infos; i++)
|
||||
{
|
||||
if (meta_rectangle_contains_rect (&screen->monitor_infos[i].rect,
|
||||
&pointer_position))
|
||||
{
|
||||
screen->last_monitor_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"Rechecked current monitor, now %d\n",
|
||||
screen->last_monitor_index);
|
||||
|
||||
}
|
||||
|
||||
return screen->last_monitor_index;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* meta_screen_get_current_monitor:
|
||||
* @screen: a #MetaScreen
|
||||
@@ -2241,11 +2147,7 @@ meta_screen_get_current_monitor (MetaScreen *screen)
|
||||
XIButtonState buttons;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
int i;
|
||||
MetaRectangle pointer_position;
|
||||
|
||||
screen->display->monitor_cache_invalidated = FALSE;
|
||||
|
||||
XIQueryPointer (screen->display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
screen->xroot,
|
||||
@@ -2260,24 +2162,7 @@ meta_screen_get_current_monitor (MetaScreen *screen)
|
||||
&group);
|
||||
free (buttons.mask);
|
||||
|
||||
pointer_position.x = root_x_return;
|
||||
pointer_position.y = root_y_return;
|
||||
pointer_position.width = pointer_position.height = 1;
|
||||
|
||||
screen->last_monitor_index = 0;
|
||||
for (i = 0; i < screen->n_monitor_infos; i++)
|
||||
{
|
||||
if (meta_rectangle_contains_rect (&screen->monitor_infos[i].rect,
|
||||
&pointer_position))
|
||||
{
|
||||
screen->last_monitor_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_XINERAMA,
|
||||
"Rechecked current monitor, now %d\n",
|
||||
screen->last_monitor_index);
|
||||
meta_screen_get_current_monitor_for_pos (screen, root_x_return, root_y_return);
|
||||
}
|
||||
|
||||
return screen->last_monitor_index;
|
||||
@@ -2959,19 +2844,15 @@ meta_screen_resize_func (MetaScreen *screen,
|
||||
meta_window_recalc_features (window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_resize (MetaScreen *screen,
|
||||
int width,
|
||||
int height)
|
||||
static void
|
||||
on_monitors_changed (MetaMonitorManager *manager,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
GSList *windows, *tmp;
|
||||
MetaMonitorInfo *old_monitor_infos;
|
||||
GSList *tmp, *windows;
|
||||
|
||||
screen->rect.width = width;
|
||||
screen->rect.height = height;
|
||||
|
||||
/* Save the old monitor infos, so they stay valid during the update */
|
||||
old_monitor_infos = screen->monitor_infos;
|
||||
meta_monitor_manager_get_screen_size (manager,
|
||||
&screen->rect.width,
|
||||
&screen->rect.height);
|
||||
|
||||
reload_monitor_infos (screen);
|
||||
set_desktop_geometry_hint (screen);
|
||||
@@ -2983,8 +2864,8 @@ meta_screen_resize (MetaScreen *screen,
|
||||
|
||||
changes.x = 0;
|
||||
changes.y = 0;
|
||||
changes.width = width;
|
||||
changes.height = height;
|
||||
changes.width = screen->rect.width;
|
||||
changes.height = screen->rect.height;
|
||||
|
||||
XConfigureWindow(screen->display->xdisplay,
|
||||
screen->guard_window,
|
||||
@@ -2994,14 +2875,15 @@ meta_screen_resize (MetaScreen *screen,
|
||||
|
||||
if (screen->display->compositor)
|
||||
meta_compositor_sync_screen_size (screen->display->compositor,
|
||||
screen, width, height);
|
||||
screen,
|
||||
screen->rect.width, screen->rect.height);
|
||||
|
||||
/* Queue a resize on all the windows */
|
||||
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
|
||||
|
||||
/* Fix up monitor for all windows on this screen */
|
||||
windows = meta_display_list_windows (screen->display,
|
||||
META_LIST_DEFAULT);
|
||||
META_LIST_INCLUDE_OVERRIDE_REDIRECT);
|
||||
for (tmp = windows; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
MetaWindow *window = tmp->data;
|
||||
@@ -3010,7 +2892,6 @@ meta_screen_resize (MetaScreen *screen,
|
||||
meta_window_update_for_monitors_changed (window);
|
||||
}
|
||||
|
||||
g_free (old_monitor_infos);
|
||||
g_slist_free (windows);
|
||||
|
||||
meta_screen_queue_check_fullscreen (screen);
|
||||
@@ -3806,3 +3687,13 @@ meta_screen_get_monitor_in_fullscreen (MetaScreen *screen,
|
||||
/* We use -1 as a flag to mean "not known yet" for notification purposes */
|
||||
return screen->monitor_infos[monitor].in_fullscreen == TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_screen_handle_xevent (MetaScreen *screen,
|
||||
XEvent *xevent)
|
||||
{
|
||||
if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <meta/util.h>
|
||||
#include <meta/main.h>
|
||||
#include "session.h"
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
@@ -531,6 +533,12 @@ die_callback (SmcConn smc_conn, SmPointer client_data)
|
||||
* Anything that wants us to go away outside of session management
|
||||
* can use kill().
|
||||
*/
|
||||
|
||||
/* All of that is true - unless we're a wayland compositor. In which
|
||||
* case the X server won't go down until we do, so we must die first.
|
||||
*/
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_quit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -37,36 +37,55 @@
|
||||
#define META_STACK_TRACKER_H
|
||||
|
||||
#include <meta/screen.h>
|
||||
#include <meta/window.h>
|
||||
|
||||
typedef struct _MetaStackTracker MetaStackTracker;
|
||||
|
||||
typedef union _MetaStackWindow
|
||||
{
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
} any;
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
Window xwindow;
|
||||
} x11;
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
MetaWindow *meta_window;
|
||||
} wayland;
|
||||
} MetaStackWindow;
|
||||
|
||||
gboolean meta_stack_window_equal (const MetaStackWindow *a,
|
||||
const MetaStackWindow *b);
|
||||
|
||||
MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen);
|
||||
void meta_stack_tracker_free (MetaStackTracker *tracker);
|
||||
|
||||
/* These functions are called when we make an X call that changes the
|
||||
* stacking order; this allows MetaStackTracker to predict stacking
|
||||
* order before it receives events back from the X server */
|
||||
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
|
||||
Window *windows,
|
||||
int n_windows,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
Window sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
Window sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *windows,
|
||||
int n_windows,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
const MetaStackWindow *sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
const MetaStackWindow *sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
|
||||
/* These functions are used to update the stack when we get events
|
||||
* reflecting changes to the stacking order */
|
||||
@@ -79,9 +98,9 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker,
|
||||
void meta_stack_tracker_configure_event (MetaStackTracker *tracker,
|
||||
XConfigureEvent *event);
|
||||
|
||||
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
|
||||
Window **windows,
|
||||
int *n_windows);
|
||||
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
|
||||
MetaStackWindow **windows,
|
||||
int *n_entries);
|
||||
|
||||
void meta_stack_tracker_sync_stack (MetaStackTracker *tracker);
|
||||
void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);
|
||||
|
544
src/core/stack.c
544
src/core/stack.c
@@ -52,7 +52,7 @@
|
||||
|
||||
#define WINDOW_IN_STACK(w) (w->stack_position >= 0)
|
||||
|
||||
static void stack_sync_to_server (MetaStack *stack);
|
||||
static void stack_sync_to_xserver (MetaStack *stack);
|
||||
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
|
||||
int position);
|
||||
static void stack_do_window_deletions (MetaStack *stack);
|
||||
@@ -71,14 +71,14 @@ meta_stack_new (MetaScreen *screen)
|
||||
stack = g_new (MetaStack, 1);
|
||||
|
||||
stack->screen = screen;
|
||||
stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
stack->sorted = NULL;
|
||||
stack->added = NULL;
|
||||
stack->removed = NULL;
|
||||
|
||||
stack->freeze_count = 0;
|
||||
stack->last_root_children_stacked = NULL;
|
||||
stack->last_all_root_children_stacked = NULL;
|
||||
|
||||
stack->n_positions = 0;
|
||||
|
||||
@@ -89,17 +89,34 @@ meta_stack_new (MetaScreen *screen)
|
||||
return stack;
|
||||
}
|
||||
|
||||
static void
|
||||
free_last_all_root_children_stacked_cache (MetaStack *stack)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < stack->last_all_root_children_stacked->len; i++)
|
||||
{
|
||||
MetaStackWindow *window = &g_array_index (stack->last_all_root_children_stacked, MetaStackWindow, i);
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
g_object_remove_weak_pointer (G_OBJECT (window->wayland.meta_window),
|
||||
(gpointer *)&window->wayland.meta_window);
|
||||
}
|
||||
|
||||
g_array_free (stack->last_all_root_children_stacked, TRUE);
|
||||
stack->last_all_root_children_stacked = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_stack_free (MetaStack *stack)
|
||||
{
|
||||
g_array_free (stack->windows, TRUE);
|
||||
g_array_free (stack->xwindows, TRUE);
|
||||
|
||||
g_list_free (stack->sorted);
|
||||
g_list_free (stack->added);
|
||||
g_list_free (stack->removed);
|
||||
|
||||
if (stack->last_root_children_stacked)
|
||||
g_array_free (stack->last_root_children_stacked, TRUE);
|
||||
if (stack->last_all_root_children_stacked)
|
||||
free_last_all_root_children_stacked_cache (stack);
|
||||
|
||||
g_free (stack);
|
||||
}
|
||||
@@ -121,7 +138,7 @@ meta_stack_add (MetaStack *stack,
|
||||
"Window %s has stack_position initialized to %d\n",
|
||||
window->desc, window->stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@@ -157,7 +174,7 @@ meta_stack_remove (MetaStack *stack,
|
||||
stack->removed = g_list_prepend (stack->removed,
|
||||
GUINT_TO_POINTER (window->frame->xwindow));
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@@ -167,7 +184,7 @@ meta_stack_update_layer (MetaStack *stack,
|
||||
{
|
||||
stack->need_relayer = TRUE;
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@@ -177,7 +194,7 @@ meta_stack_update_transient (MetaStack *stack,
|
||||
{
|
||||
stack->need_constrain = TRUE;
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@@ -206,7 +223,7 @@ meta_stack_raise (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, max_stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@@ -234,7 +251,7 @@ meta_stack_lower (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, min_stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@@ -250,7 +267,7 @@ meta_stack_thaw (MetaStack *stack)
|
||||
g_return_if_fail (stack->freeze_count > 0);
|
||||
|
||||
stack->freeze_count -= 1;
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@@ -278,7 +295,7 @@ static gboolean
|
||||
is_focused_foreach (MetaWindow *window,
|
||||
void *data)
|
||||
{
|
||||
if (window == window->display->expected_focus_window)
|
||||
if (window->has_focus)
|
||||
{
|
||||
*((gboolean*) data) = TRUE;
|
||||
return FALSE;
|
||||
@@ -335,11 +352,11 @@ get_standalone_layer (MetaWindow *window)
|
||||
layer = META_LAYER_BOTTOM;
|
||||
else if (window->fullscreen &&
|
||||
(focused_transient ||
|
||||
window == window->display->expected_focus_window ||
|
||||
window->display->expected_focus_window == NULL ||
|
||||
(window->display->expected_focus_window != NULL &&
|
||||
window == window->display->focus_window ||
|
||||
window->display->focus_window == NULL ||
|
||||
(window->display->focus_window != NULL &&
|
||||
windows_on_different_monitor (window,
|
||||
window->display->expected_focus_window))))
|
||||
window->display->focus_window))))
|
||||
layer = META_LAYER_FULLSCREEN;
|
||||
else if (window->wm_state_above && !META_WINDOW_MAXIMIZED (window))
|
||||
layer = META_LAYER_TOP;
|
||||
@@ -829,7 +846,7 @@ stack_do_window_deletions (MetaStack *stack)
|
||||
/* We go from the end figuring removals are more
|
||||
* likely to be recent.
|
||||
*/
|
||||
i = stack->windows->len;
|
||||
i = stack->xwindows->len;
|
||||
while (i > 0)
|
||||
{
|
||||
--i;
|
||||
@@ -840,9 +857,9 @@ stack_do_window_deletions (MetaStack *stack)
|
||||
* both the window->xwindow and window->frame->xwindow
|
||||
* in the removal list.
|
||||
*/
|
||||
if (xwindow == g_array_index (stack->windows, Window, i))
|
||||
if (xwindow == g_array_index (stack->xwindows, Window, i))
|
||||
{
|
||||
g_array_remove_index (stack->windows, i);
|
||||
g_array_remove_index (stack->xwindows, i);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
@@ -871,10 +888,10 @@ stack_do_window_additions (MetaStack *stack)
|
||||
"Adding %d windows to sorted list\n",
|
||||
n_added);
|
||||
|
||||
old_size = stack->windows->len;
|
||||
g_array_set_size (stack->windows, old_size + n_added);
|
||||
old_size = stack->xwindows->len;
|
||||
g_array_set_size (stack->xwindows, old_size + n_added);
|
||||
|
||||
end = &g_array_index (stack->windows, Window, old_size);
|
||||
end = &g_array_index (stack->xwindows, Window, old_size);
|
||||
|
||||
/* stack->added has the most recent additions at the
|
||||
* front of the list, so we need to reverse it
|
||||
@@ -1029,6 +1046,102 @@ stack_ensure_sorted (MetaStack *stack)
|
||||
stack_do_resort (stack);
|
||||
}
|
||||
|
||||
static MetaStackWindow *
|
||||
find_top_most_managed_window (MetaScreen *screen,
|
||||
const MetaStackWindow *ignore)
|
||||
{
|
||||
MetaStackTracker *stack_tracker = screen->stack_tracker;
|
||||
MetaStackWindow *windows;
|
||||
int n_windows;
|
||||
int i;
|
||||
|
||||
meta_stack_tracker_get_stack (stack_tracker,
|
||||
&windows, &n_windows);
|
||||
|
||||
/* Children are in order from bottom to top. We want to
|
||||
* find the topmost managed child, then configure
|
||||
* our window to be above it.
|
||||
*/
|
||||
for (i = n_windows -1; i >= 0; i--)
|
||||
{
|
||||
MetaStackWindow *other_window = &windows[i];
|
||||
|
||||
if (other_window->any.type == ignore->any.type &&
|
||||
((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
other_window->x11.xwindow == ignore->x11.xwindow) ||
|
||||
other_window->wayland.meta_window == ignore->wayland.meta_window))
|
||||
{
|
||||
/* Do nothing. This means we're already the topmost managed
|
||||
* window, but it DOES NOT mean we are already just above
|
||||
* the topmost managed window. This is important because if
|
||||
* an override redirect window is up, and we map a new
|
||||
* managed window, the new window is probably above the old
|
||||
* popup by default, and we want to push it below that
|
||||
* popup. So keep looking for a sibling managed window
|
||||
* to be moved below.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
MetaWindow *other = meta_display_lookup_x_window (screen->display,
|
||||
other_window->x11.xwindow);
|
||||
|
||||
if (other != NULL && !other->override_redirect)
|
||||
return other_window;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* All wayland windows are currently considered "managed"
|
||||
* TODO: consider wayland pop-up windows like override
|
||||
* redirect windows here. */
|
||||
return other_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* When moving an X window we sometimes need an X based sibling.
|
||||
*
|
||||
* If the given sibling is X based this function returns it back
|
||||
* otherwise it searches downwards looking for the nearest X window.
|
||||
*
|
||||
* If no X based sibling could be found return NULL. */
|
||||
static MetaStackWindow *
|
||||
find_x11_sibling_downwards (MetaScreen *screen,
|
||||
MetaStackWindow *sibling)
|
||||
{
|
||||
MetaStackTracker *stack_tracker = screen->stack_tracker;
|
||||
MetaStackWindow *windows;
|
||||
int n_windows;
|
||||
int i;
|
||||
|
||||
if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
return sibling;
|
||||
|
||||
meta_stack_tracker_get_stack (stack_tracker,
|
||||
&windows, &n_windows);
|
||||
|
||||
/* NB: Children are in order from bottom to top and we
|
||||
* want to search downwards for the nearest X window.
|
||||
*/
|
||||
|
||||
for (i = n_windows - 1; i >= 0; i--)
|
||||
if (meta_stack_window_equal (&windows[i], sibling))
|
||||
break;
|
||||
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
return &windows[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* raise_window_relative_to_managed_windows:
|
||||
*
|
||||
@@ -1053,84 +1166,74 @@ stack_ensure_sorted (MetaStack *stack)
|
||||
*/
|
||||
static void
|
||||
raise_window_relative_to_managed_windows (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
const MetaStackWindow *window)
|
||||
{
|
||||
gulong serial = 0;
|
||||
MetaStackWindow *sibling;
|
||||
|
||||
Window *children;
|
||||
int n_children;
|
||||
int i;
|
||||
|
||||
meta_stack_tracker_get_stack (screen->stack_tracker,
|
||||
&children, &n_children);
|
||||
|
||||
/* Children are in order from bottom to top. We want to
|
||||
* find the topmost managed child, then configure
|
||||
* our window to be above it.
|
||||
*/
|
||||
i = n_children - 1;
|
||||
while (i >= 0)
|
||||
sibling = find_top_most_managed_window (screen, window);
|
||||
if (!sibling)
|
||||
{
|
||||
if (children[i] == xwindow)
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
/* Do nothing. This means we're already the topmost managed
|
||||
* window, but it DOES NOT mean we are already just above
|
||||
* the topmost managed window. This is important because if
|
||||
* an override redirect window is up, and we map a new
|
||||
* managed window, the new window is probably above the old
|
||||
* popup by default, and we want to push it below that
|
||||
* popup. So keep looking for a sibling managed window
|
||||
* to be moved below.
|
||||
*/
|
||||
serial = XNextRequest (screen->display->xdisplay);
|
||||
meta_error_trap_push (screen->display);
|
||||
XLowerWindow (screen->display->xdisplay,
|
||||
window->x11.xwindow);
|
||||
meta_error_trap_pop (screen->display);
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaWindow *other = meta_display_lookup_x_window (screen->display,
|
||||
children[i]);
|
||||
if (other != NULL && !other->override_redirect)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
|
||||
/* children[i] is the topmost managed child */
|
||||
/* No sibling to use, just lower ourselves to the bottom
|
||||
* to be sure we're below any override redirect windows.
|
||||
*/
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
window,
|
||||
serial);
|
||||
return;
|
||||
}
|
||||
|
||||
/* window is the topmost managed child */
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Moving 0x%lx above topmost managed child window 0x%lx\n",
|
||||
xwindow, children[i]);
|
||||
window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0,
|
||||
sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0);
|
||||
|
||||
changes.sibling = children[i];
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling);
|
||||
serial = XNextRequest (screen->display->xdisplay);
|
||||
|
||||
if (x11_sibling)
|
||||
{
|
||||
changes.sibling = x11_sibling->x11.xwindow;
|
||||
changes.stack_mode = Above;
|
||||
|
||||
meta_error_trap_push (screen->display);
|
||||
meta_stack_tracker_record_raise_above (screen->stack_tracker,
|
||||
xwindow,
|
||||
children[i],
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
XConfigureWindow (screen->display->xdisplay,
|
||||
xwindow,
|
||||
window->x11.xwindow,
|
||||
CWSibling | CWStackMode,
|
||||
&changes);
|
||||
meta_error_trap_pop (screen->display);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
else
|
||||
{
|
||||
/* No sibling to use, just lower ourselves to the bottom
|
||||
* to be sure we're below any override redirect windows.
|
||||
*/
|
||||
meta_error_trap_push (screen->display);
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
xwindow,
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
XLowerWindow (screen->display->xdisplay,
|
||||
xwindow);
|
||||
window->x11.xwindow);
|
||||
meta_error_trap_pop (screen->display);
|
||||
}
|
||||
}
|
||||
|
||||
meta_stack_tracker_record_raise_above (screen->stack_tracker,
|
||||
window,
|
||||
sibling,
|
||||
serial);
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_sync_to_server:
|
||||
*
|
||||
@@ -1145,13 +1248,16 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
|
||||
* job of computing the minimal set of stacking requests needed.
|
||||
*/
|
||||
static void
|
||||
stack_sync_to_server (MetaStack *stack)
|
||||
stack_sync_to_xserver (MetaStack *stack)
|
||||
{
|
||||
GArray *stacked;
|
||||
GArray *root_children_stacked;
|
||||
GArray *x11_stacked;
|
||||
GArray *x11_root_children_stacked;
|
||||
GArray *all_root_children_stacked; /* wayland OR x11 */
|
||||
GList *tmp;
|
||||
GArray *all_hidden;
|
||||
GArray *x11_hidden;
|
||||
GArray *x11_hidden_stack_windows;
|
||||
int n_override_redirect = 0;
|
||||
MetaStackWindow guard_stack_window;
|
||||
|
||||
/* Bail out if frozen */
|
||||
if (stack->freeze_count > 0)
|
||||
@@ -1166,13 +1272,17 @@ stack_sync_to_server (MetaStack *stack)
|
||||
* _NET hints, and "root_children_stacked" is in top-to-bottom
|
||||
* order for XRestackWindows()
|
||||
*/
|
||||
stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
|
||||
x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
|
||||
x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
/* The screen guard window sits above all hidden windows and acts as
|
||||
* a barrier to input reaching these windows. */
|
||||
g_array_append_val (all_hidden, stack->screen->guard_window);
|
||||
g_array_append_val (x11_hidden, stack->screen->guard_window);
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
|
||||
meta_push_no_msg_prefix ();
|
||||
@@ -1181,6 +1291,9 @@ stack_sync_to_server (MetaStack *stack)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
Window top_level_window;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
stack_window.any.type = w->client_type;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
||||
w->layer, w->stack_position, w->desc);
|
||||
@@ -1189,60 +1302,93 @@ stack_sync_to_server (MetaStack *stack)
|
||||
if (w->override_redirect)
|
||||
n_override_redirect++;
|
||||
else
|
||||
g_array_prepend_val (stacked, w->xwindow);
|
||||
g_array_prepend_val (x11_stacked, w->xwindow);
|
||||
|
||||
if (w->frame)
|
||||
top_level_window = w->frame->xwindow;
|
||||
else
|
||||
top_level_window = w->xwindow;
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
stack_window.x11.xwindow = top_level_window;
|
||||
else
|
||||
stack_window.wayland.meta_window = w;
|
||||
|
||||
/* We don't restack hidden windows along with the rest, though they are
|
||||
* reflected in the _NET hints. Hidden windows all get pushed below
|
||||
* the screens fullscreen guard_window. */
|
||||
if (w->hidden)
|
||||
{
|
||||
g_array_append_val (all_hidden, top_level_window);
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = top_level_window;
|
||||
|
||||
g_array_append_val (x11_hidden_stack_windows, stack_window);
|
||||
g_array_append_val (x11_hidden, top_level_window);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
g_array_append_val (all_root_children_stacked, stack_window);
|
||||
|
||||
/* build XRestackWindows() array from top to bottom */
|
||||
g_array_append_val (root_children_stacked, top_level_window);
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
g_array_append_val (x11_root_children_stacked, top_level_window);
|
||||
else
|
||||
{
|
||||
MetaStackWindow *new;
|
||||
|
||||
/* So we can determine later if a cached stack window is
|
||||
* stale because the corresponding window has been freed we
|
||||
* associate a weak pointer with the new window. */
|
||||
new = &g_array_index (all_root_children_stacked, MetaStackWindow, all_root_children_stacked->len - 1);
|
||||
g_object_add_weak_pointer (G_OBJECT (new->wayland.meta_window),
|
||||
(gpointer *)&new->wayland.meta_window);
|
||||
}
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "\n");
|
||||
meta_pop_no_msg_prefix ();
|
||||
|
||||
/* All windows should be in some stacking order */
|
||||
if (stacked->len != stack->windows->len - n_override_redirect)
|
||||
/* All X windows should be in some stacking order */
|
||||
if (x11_stacked->len != stack->xwindows->len - n_override_redirect)
|
||||
meta_bug ("%u windows stacked, %u windows exist in stack\n",
|
||||
stacked->len, stack->windows->len);
|
||||
x11_stacked->len, stack->xwindows->len);
|
||||
|
||||
/* Sync to server */
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
||||
root_children_stacked->len);
|
||||
all_root_children_stacked->len);
|
||||
|
||||
meta_error_trap_push (stack->screen->display);
|
||||
|
||||
if (stack->last_root_children_stacked == NULL)
|
||||
if (stack->last_all_root_children_stacked == NULL)
|
||||
{
|
||||
/* Just impose our stack, we don't know the previous state.
|
||||
* This involves a ton of circulate requests and may flicker.
|
||||
*/
|
||||
meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
|
||||
|
||||
if (root_children_stacked->len > 0)
|
||||
if (all_root_children_stacked->len > 1)
|
||||
{
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *) root_children_stacked->data,
|
||||
root_children_stacked->len,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
gulong serial = 0;
|
||||
if (x11_root_children_stacked->len > 1)
|
||||
{
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *) root_children_stacked->data,
|
||||
root_children_stacked->len);
|
||||
(Window *) x11_root_children_stacked->data,
|
||||
x11_root_children_stacked->len);
|
||||
}
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(MetaStackWindow *) all_root_children_stacked->data,
|
||||
all_root_children_stacked->len,
|
||||
serial);
|
||||
}
|
||||
}
|
||||
else if (root_children_stacked->len > 0)
|
||||
else if (all_root_children_stacked->len > 0)
|
||||
{
|
||||
/* Try to do minimal window moves to get the stack in order */
|
||||
/* A point of note: these arrays include frames not client windows,
|
||||
@@ -1250,28 +1396,34 @@ stack_sync_to_server (MetaStack *stack)
|
||||
* was saved, then we may have inefficiency, but I don't think things
|
||||
* break...
|
||||
*/
|
||||
const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
|
||||
const Window *new_stack = (Window *) root_children_stacked->data;
|
||||
const int old_len = stack->last_root_children_stacked->len;
|
||||
const int new_len = root_children_stacked->len;
|
||||
const Window *oldp = old_stack;
|
||||
const Window *newp = new_stack;
|
||||
const Window *old_end = old_stack + old_len;
|
||||
const Window *new_end = new_stack + new_len;
|
||||
Window last_window = None;
|
||||
|
||||
const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data;
|
||||
const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data;
|
||||
const int old_len = stack->last_all_root_children_stacked->len;
|
||||
const int new_len = all_root_children_stacked->len;
|
||||
const MetaStackWindow *oldp = old_stack;
|
||||
const MetaStackWindow *newp = new_stack;
|
||||
const MetaStackWindow *old_end = old_stack + old_len;
|
||||
const MetaStackWindow *new_end = new_stack + new_len;
|
||||
Window last_xwindow = None;
|
||||
const MetaStackWindow *last_window = NULL;
|
||||
|
||||
while (oldp != old_end &&
|
||||
newp != new_end)
|
||||
{
|
||||
if (*oldp == *newp)
|
||||
if (meta_stack_window_equal (oldp, newp))
|
||||
{
|
||||
/* Stacks are the same here, move on */
|
||||
++oldp;
|
||||
last_window = *newp;
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
last_xwindow = newp->x11.xwindow;
|
||||
last_window = newp;
|
||||
++newp;
|
||||
}
|
||||
else if (meta_display_lookup_x_window (stack->screen->display,
|
||||
*oldp) == NULL)
|
||||
else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
meta_display_lookup_x_window (stack->screen->display,
|
||||
oldp->x11.xwindow) == NULL) ||
|
||||
(oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
|
||||
oldp->wayland.meta_window == NULL))
|
||||
{
|
||||
/* *oldp is no longer known to us (probably destroyed),
|
||||
* so we can just skip it
|
||||
@@ -1280,75 +1432,161 @@ stack_sync_to_server (MetaStack *stack)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move *newp below last_window */
|
||||
if (last_window == None)
|
||||
/* Move *newp below the last_window */
|
||||
if (!last_window)
|
||||
{
|
||||
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);
|
||||
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n",
|
||||
newp->x11.xwindow);
|
||||
|
||||
raise_window_relative_to_managed_windows (stack->screen,
|
||||
*newp);
|
||||
raise_window_relative_to_managed_windows (stack->screen, newp);
|
||||
}
|
||||
else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
last_xwindow == None)
|
||||
{
|
||||
/* In this case we have an X window that we need to
|
||||
* put below a wayland window and this is the
|
||||
* topmost X window. */
|
||||
|
||||
/* In X terms (because this is the topmost X window)
|
||||
* we want to
|
||||
* raise_window_relative_to_managed_windows() to
|
||||
* ensure the X window is below override-redirect
|
||||
* pop-up windows.
|
||||
*
|
||||
* In Wayland terms we just want to ensure
|
||||
* newp is lowered below last_window (which
|
||||
* notably doesn't require an X request because we
|
||||
* know last_window isn't an X window).
|
||||
*/
|
||||
|
||||
raise_window_relative_to_managed_windows (stack->screen, newp);
|
||||
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
newp, last_window,
|
||||
0); /* no x request serial */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This means that if last_window is dead, but not
|
||||
gulong serial = 0;
|
||||
|
||||
/* This means that if last_xwindow is dead, but not
|
||||
* *newp, then we fail to restack *newp; but on
|
||||
* unmanaging last_window, we'll fix it up.
|
||||
* unmanaging last_xwindow, we'll fix it up.
|
||||
*/
|
||||
|
||||
XWindowChanges changes;
|
||||
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
|
||||
newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0,
|
||||
last_xwindow);
|
||||
|
||||
changes.sibling = last_window;
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
|
||||
changes.sibling = last_xwindow;
|
||||
changes.stack_mode = Below;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
|
||||
*newp, last_window);
|
||||
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
*newp, last_window,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XConfigureWindow (stack->screen->display->xdisplay,
|
||||
*newp,
|
||||
newp->x11.xwindow,
|
||||
CWSibling | CWStackMode,
|
||||
&changes);
|
||||
}
|
||||
|
||||
last_window = *newp;
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
newp, last_window,
|
||||
serial);
|
||||
}
|
||||
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
last_xwindow = newp->x11.xwindow;
|
||||
last_window = newp;
|
||||
++newp;
|
||||
}
|
||||
}
|
||||
|
||||
if (newp != new_end)
|
||||
{
|
||||
const MetaStackWindow *x_ref;
|
||||
unsigned long serial = 0;
|
||||
|
||||
/* Restack remaining windows */
|
||||
meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
|
||||
(int) (new_end - newp));
|
||||
|
||||
/* rewind until we find the last stacked X window that we can use
|
||||
* as a reference point for re-stacking remaining X windows */
|
||||
if (newp != new_stack)
|
||||
for (x_ref = newp - 1;
|
||||
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
|
||||
x_ref--)
|
||||
;
|
||||
else
|
||||
x_ref = new_stack;
|
||||
|
||||
/* If we didn't find an X window looking backwards then walk forwards
|
||||
* through the remaining windows to find the first remaining X window
|
||||
* instead. */
|
||||
if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
for (x_ref = newp;
|
||||
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
|
||||
x_ref++)
|
||||
;
|
||||
}
|
||||
|
||||
/* If there are any X windows remaining unstacked then restack them */
|
||||
if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = x11_root_children_stacked->len - 1; i; i--)
|
||||
{
|
||||
Window *reference = &g_array_index (x11_root_children_stacked, Window, i);
|
||||
|
||||
if (*reference == x_ref->x11.xwindow)
|
||||
{
|
||||
int n = x11_root_children_stacked->len - i;
|
||||
|
||||
/* There's no point restacking if there's only one X window */
|
||||
if (n == 1)
|
||||
break;
|
||||
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
reference, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to include an already-stacked window
|
||||
* in the restack call, so we get in the proper position
|
||||
* with respect to it.
|
||||
*/
|
||||
if (newp != new_stack)
|
||||
--newp;
|
||||
newp = MIN (newp - 1, x_ref);
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *) newp, new_end - newp,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *) newp, new_end - newp);
|
||||
newp, new_end - newp,
|
||||
serial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Push hidden windows to the bottom of the stack under the guard window */
|
||||
/* Push hidden X windows to the bottom of the stack under the guard window */
|
||||
guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
guard_stack_window.x11.xwindow = stack->screen->guard_window;
|
||||
meta_stack_tracker_record_lower (stack->screen->stack_tracker,
|
||||
stack->screen->guard_window,
|
||||
&guard_stack_window,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *)all_hidden->data,
|
||||
all_hidden->len,
|
||||
(MetaStackWindow *)x11_hidden_stack_windows->data,
|
||||
x11_hidden_stack_windows->len,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *)all_hidden->data,
|
||||
all_hidden->len);
|
||||
g_array_free (all_hidden, TRUE);
|
||||
(Window *)x11_hidden->data,
|
||||
x11_hidden->len);
|
||||
g_array_free (x11_hidden, TRUE);
|
||||
g_array_free (x11_hidden_stack_windows, TRUE);
|
||||
|
||||
meta_error_trap_pop (stack->screen->display);
|
||||
/* on error, a window was destroyed; it should eventually
|
||||
@@ -1363,21 +1601,23 @@ stack_sync_to_server (MetaStack *stack)
|
||||
stack->screen->display->atom__NET_CLIENT_LIST,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stack->windows->data,
|
||||
stack->windows->len);
|
||||
(unsigned char *)stack->xwindows->data,
|
||||
stack->xwindows->len);
|
||||
XChangeProperty (stack->screen->display->xdisplay,
|
||||
stack->screen->xroot,
|
||||
stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stacked->data,
|
||||
stacked->len);
|
||||
(unsigned char *)x11_stacked->data,
|
||||
x11_stacked->len);
|
||||
|
||||
g_array_free (stacked, TRUE);
|
||||
g_array_free (x11_stacked, TRUE);
|
||||
|
||||
if (stack->last_root_children_stacked)
|
||||
g_array_free (stack->last_root_children_stacked, TRUE);
|
||||
stack->last_root_children_stacked = root_children_stacked;
|
||||
if (stack->last_all_root_children_stacked)
|
||||
free_last_all_root_children_stacked_cache (stack);
|
||||
stack->last_all_root_children_stacked = all_root_children_stacked;
|
||||
|
||||
g_array_free (x11_root_children_stacked, TRUE);
|
||||
|
||||
/* That was scary... */
|
||||
}
|
||||
@@ -1738,7 +1978,7 @@ meta_stack_set_positions (MetaStack *stack,
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Reset the stack positions of (nearly) all windows\n");
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@@ -1801,7 +2041,7 @@ meta_window_set_stack_position (MetaWindow *window,
|
||||
int position)
|
||||
{
|
||||
meta_window_set_stack_position_no_sync (window, position);
|
||||
stack_sync_to_server (window->screen->stack);
|
||||
stack_sync_to_xserver (window->screen->stack);
|
||||
meta_stack_update_window_tile_matches (window->screen->stack,
|
||||
window->screen->active_workspace);
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ struct _MetaStack
|
||||
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
||||
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
||||
*/
|
||||
GArray *windows;
|
||||
GArray *xwindows;
|
||||
|
||||
/** The MetaWindows of the windows we manage, sorted in order. */
|
||||
GList *sorted;
|
||||
@@ -99,7 +99,7 @@ struct _MetaStack
|
||||
* The last-known stack of all windows, bottom to top. We cache it here
|
||||
* so that subsequent times we'll be able to do incremental moves.
|
||||
*/
|
||||
GArray *last_root_children_stacked;
|
||||
GArray *last_all_root_children_stacked;
|
||||
|
||||
/**
|
||||
* Number of stack positions; same as the length of added, but
|
||||
|
@@ -55,6 +55,7 @@ static gint verbose_topics = 0;
|
||||
static gboolean is_debugging = FALSE;
|
||||
static gboolean replace_current = FALSE;
|
||||
static int no_prefix = 0;
|
||||
static gboolean is_wayland_compositor = FALSE;
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static FILE* logfile = NULL;
|
||||
@@ -194,6 +195,18 @@ meta_set_replace_current_wm (gboolean setting)
|
||||
replace_current = setting;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_is_wayland_compositor (void)
|
||||
{
|
||||
return is_wayland_compositor;
|
||||
}
|
||||
|
||||
void
|
||||
meta_set_is_wayland_compositor (gboolean value)
|
||||
{
|
||||
is_wayland_compositor = value;
|
||||
}
|
||||
|
||||
char *
|
||||
meta_g_utf8_strndup (const gchar *src,
|
||||
gsize n)
|
||||
@@ -332,6 +345,8 @@ topic_name (MetaDebugTopic topic)
|
||||
return "COMPOSITOR";
|
||||
case META_DEBUG_EDGE_RESISTANCE:
|
||||
return "EDGE_RESISTANCE";
|
||||
case META_DEBUG_DBUS:
|
||||
return "DBUS";
|
||||
case META_DEBUG_VERBOSE:
|
||||
return "VERBOSE";
|
||||
}
|
||||
@@ -637,8 +652,13 @@ meta_show_dialog (const char *type,
|
||||
|
||||
append_argument (args, "zenity");
|
||||
append_argument (args, type);
|
||||
append_argument (args, "--display");
|
||||
append_argument (args, display);
|
||||
|
||||
if (display)
|
||||
{
|
||||
append_argument (args, "--display");
|
||||
append_argument (args, display);
|
||||
}
|
||||
|
||||
append_argument (args, "--class");
|
||||
append_argument (args, "mutter-dialog");
|
||||
append_argument (args, "--title");
|
||||
|
@@ -44,6 +44,8 @@
|
||||
#include <X11/Xutil.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include "meta-wayland-types.h"
|
||||
|
||||
typedef struct _MetaWindowQueue MetaWindowQueue;
|
||||
|
||||
@@ -69,6 +71,7 @@ typedef enum {
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
|
||||
} MetaBypassCompositorHintValue;
|
||||
|
||||
|
||||
struct _MetaWindow
|
||||
{
|
||||
GObject parent_instance;
|
||||
@@ -77,6 +80,10 @@ struct _MetaWindow
|
||||
MetaScreen *screen;
|
||||
const MetaMonitorInfo *monitor;
|
||||
MetaWorkspace *workspace;
|
||||
MetaWindowClientType client_type;
|
||||
#ifdef HAVE_WAYLAND
|
||||
MetaWaylandSurface *surface;
|
||||
#endif
|
||||
Window xwindow;
|
||||
/* may be NULL! not all windows get decorated */
|
||||
MetaFrame *frame;
|
||||
@@ -121,6 +128,7 @@ struct _MetaWindow
|
||||
Window xtransient_for;
|
||||
Window xgroup_leader;
|
||||
Window xclient_leader;
|
||||
MetaWindow *transient_for;
|
||||
|
||||
/* Initial workspace property */
|
||||
int initial_workspace;
|
||||
@@ -165,7 +173,7 @@ struct _MetaWindow
|
||||
* been overridden (via a client message), the window will cover the union of
|
||||
* these monitors. If not, this is the single monitor which the window's
|
||||
* origin is on. */
|
||||
long fullscreen_monitors[4];
|
||||
gint fullscreen_monitors[4];
|
||||
|
||||
/* Whether we're trying to constrain the window to be fully onscreen */
|
||||
guint require_fully_onscreen : 1;
|
||||
@@ -277,7 +285,7 @@ struct _MetaWindow
|
||||
/* EWHH demands attention flag */
|
||||
guint wm_state_demands_attention : 1;
|
||||
|
||||
/* this flag tracks receipt of focus_in focus_out */
|
||||
/* TRUE iff window == window->display->focus_window */
|
||||
guint has_focus : 1;
|
||||
|
||||
/* Have we placed this window? */
|
||||
@@ -325,9 +333,6 @@ struct _MetaWindow
|
||||
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
|
||||
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
|
||||
|
||||
/* has a shape mask */
|
||||
guint has_shape : 1;
|
||||
|
||||
/* icon props have changed */
|
||||
guint need_reread_icon : 1;
|
||||
|
||||
@@ -349,9 +354,15 @@ struct _MetaWindow
|
||||
/* if non-NULL, the bounds of the window frame */
|
||||
cairo_region_t *frame_bounds;
|
||||
|
||||
/* if non-NULL, the bounding shape region of the window */
|
||||
cairo_region_t *shape_region;
|
||||
|
||||
/* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */
|
||||
cairo_region_t *opaque_region;
|
||||
|
||||
/* the input shape region for picking */
|
||||
cairo_region_t *input_region;
|
||||
|
||||
/* if TRUE, the we have the new form of sync request counter which
|
||||
* also handles application frames */
|
||||
guint extended_sync_request_counter : 1;
|
||||
@@ -394,6 +405,15 @@ struct _MetaWindow
|
||||
*/
|
||||
MetaRectangle rect;
|
||||
|
||||
/* The size we want the window to be (i.e. what we last asked
|
||||
* the client to configure).
|
||||
* This is only used for wayland clients.
|
||||
*/
|
||||
MetaRectangle expected_rect;
|
||||
|
||||
gboolean has_custom_frame_extents;
|
||||
GtkBorder custom_frame_extents;
|
||||
|
||||
/* The geometry to restore when we unmaximize. The position is in
|
||||
* root window coords, even if there's a frame, which contrasts with
|
||||
* window->rect above. Note that this gives the position and size
|
||||
@@ -487,6 +507,10 @@ MetaWindow* meta_window_new_with_attrs (MetaDisplay *display,
|
||||
gboolean must_be_viewable,
|
||||
MetaCompEffect effect,
|
||||
XWindowAttributes *attrs);
|
||||
MetaWindow *meta_window_new_for_wayland (MetaDisplay *display,
|
||||
int width,
|
||||
int height,
|
||||
MetaWaylandSurface *surface);
|
||||
void meta_window_unmanage (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
void meta_window_calc_showing (MetaWindow *window);
|
||||
@@ -584,15 +608,19 @@ void meta_window_move_resize_request(MetaWindow *window,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
void meta_window_move_resize_wayland (MetaWindow *window,
|
||||
int width,
|
||||
int height,
|
||||
int dx,
|
||||
int dy);
|
||||
gboolean meta_window_configure_request (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_property_notify (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_client_message (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_notify_focus (MetaWindow *window,
|
||||
XIEnterEvent *event);
|
||||
void meta_window_lost_focus (MetaWindow *window);
|
||||
void meta_window_set_focused_internal (MetaWindow *window,
|
||||
gboolean focused);
|
||||
|
||||
void meta_window_set_current_workspace_hint (MetaWindow *window);
|
||||
|
||||
@@ -615,8 +643,8 @@ void meta_window_update_sync_request_counter (MetaWindow *window,
|
||||
gint64 new_counter_value);
|
||||
#endif /* HAVE_XSYNC */
|
||||
|
||||
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
||||
XIDeviceEvent *xev);
|
||||
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
||||
const ClutterEvent *event);
|
||||
|
||||
GList* meta_window_get_workspaces (MetaWindow *window);
|
||||
|
||||
@@ -663,7 +691,6 @@ void meta_window_update_icon_now (MetaWindow *window);
|
||||
|
||||
void meta_window_update_role (MetaWindow *window);
|
||||
void meta_window_update_net_wm_type (MetaWindow *window);
|
||||
void meta_window_update_opaque_region (MetaWindow *window);
|
||||
void meta_window_update_for_monitors_changed (MetaWindow *window);
|
||||
void meta_window_update_on_all_workspaces (MetaWindow *window);
|
||||
|
||||
@@ -677,4 +704,32 @@ void meta_window_compute_tile_match (MetaWindow *window);
|
||||
|
||||
gboolean meta_window_updates_are_frozen (MetaWindow *window);
|
||||
|
||||
void meta_window_set_opaque_region (MetaWindow *window,
|
||||
cairo_region_t *region);
|
||||
void meta_window_update_opaque_region_x11 (MetaWindow *window);
|
||||
|
||||
void meta_window_set_input_region (MetaWindow *window,
|
||||
cairo_region_t *region);
|
||||
void meta_window_update_input_region_x11 (MetaWindow *window);
|
||||
|
||||
void meta_window_set_shape_region (MetaWindow *window,
|
||||
cairo_region_t *region);
|
||||
void meta_window_update_shape_region_x11 (MetaWindow *window);
|
||||
|
||||
void meta_window_set_title (MetaWindow *window,
|
||||
const char *title);
|
||||
void meta_window_set_wm_class (MetaWindow *window,
|
||||
const char *wm_class,
|
||||
const char *wm_instance);
|
||||
void meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
||||
const char *application_id,
|
||||
const char *unique_bus_name,
|
||||
const char *appmenu_path,
|
||||
const char *menubar_path,
|
||||
const char *application_object_path,
|
||||
const char *window_object_path);
|
||||
|
||||
void meta_window_set_transient_for (MetaWindow *window,
|
||||
MetaWindow *parent);
|
||||
|
||||
#endif
|
||||
|
@@ -289,6 +289,35 @@ reload_icon_geometry (MetaWindow *window,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reload_gtk_frame_extents (MetaWindow *window,
|
||||
MetaPropValue *value,
|
||||
gboolean initial)
|
||||
{
|
||||
if (value->type != META_PROP_VALUE_INVALID)
|
||||
{
|
||||
if (value->v.cardinal_list.n_cardinals != 4)
|
||||
{
|
||||
meta_verbose ("_GTK_FRAME_EXTENTS on %s has %d values instead of 4\n",
|
||||
window->desc, value->v.cardinal_list.n_cardinals);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkBorder *extents = &window->custom_frame_extents;
|
||||
|
||||
window->has_custom_frame_extents = TRUE;
|
||||
extents->left = (int)value->v.cardinal_list.cardinals[0];
|
||||
extents->right = (int)value->v.cardinal_list.cardinals[1];
|
||||
extents->top = (int)value->v.cardinal_list.cardinals[2];
|
||||
extents->bottom = (int)value->v.cardinal_list.cardinals[3];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window->has_custom_frame_extents = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reload_struts (MetaWindow *window,
|
||||
MetaPropValue *value,
|
||||
@@ -460,28 +489,19 @@ static void
|
||||
set_window_title (MetaWindow *window,
|
||||
const char *title)
|
||||
{
|
||||
char *str;
|
||||
char *new_title = NULL;
|
||||
|
||||
gboolean modified =
|
||||
set_title_text (window,
|
||||
window->using_net_wm_visible_name,
|
||||
title,
|
||||
window->display->atom__NET_WM_VISIBLE_NAME,
|
||||
&window->title);
|
||||
&new_title);
|
||||
window->using_net_wm_visible_name = modified;
|
||||
|
||||
/* strndup is a hack since GNU libc has broken %.10s */
|
||||
str = g_strndup (window->title, 10);
|
||||
g_free (window->desc);
|
||||
window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str);
|
||||
g_free (str);
|
||||
meta_window_set_title (window, new_title);
|
||||
|
||||
if (window->frame)
|
||||
meta_ui_set_frame_title (window->screen->ui,
|
||||
window->frame->xwindow,
|
||||
window->title);
|
||||
|
||||
g_object_notify (G_OBJECT (window), "title");
|
||||
g_free (new_title);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -536,7 +556,7 @@ reload_opaque_region (MetaWindow *window,
|
||||
MetaPropValue *value,
|
||||
gboolean initial)
|
||||
{
|
||||
meta_window_update_opaque_region (window);
|
||||
meta_window_update_opaque_region_x11 (window);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -846,23 +866,15 @@ reload_wm_class (MetaWindow *window,
|
||||
MetaPropValue *value,
|
||||
gboolean initial)
|
||||
{
|
||||
if (window->res_class)
|
||||
g_free (window->res_class);
|
||||
if (window->res_name)
|
||||
g_free (window->res_name);
|
||||
|
||||
window->res_class = NULL;
|
||||
window->res_name = NULL;
|
||||
|
||||
if (value->type != META_PROP_VALUE_INVALID)
|
||||
{
|
||||
if (value->v.class_hint.res_name)
|
||||
window->res_name = g_strdup (value->v.class_hint.res_name);
|
||||
|
||||
if (value->v.class_hint.res_class)
|
||||
window->res_class = g_strdup (value->v.class_hint.res_class);
|
||||
|
||||
g_object_notify (G_OBJECT (window), "wm-class");
|
||||
{
|
||||
meta_window_set_wm_class (window,
|
||||
value->v.class_hint.res_class,
|
||||
value->v.class_hint.res_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_window_set_wm_class (window, NULL, NULL);
|
||||
}
|
||||
|
||||
meta_verbose ("Window %s class: '%s' name: '%s'\n",
|
||||
@@ -1542,9 +1554,6 @@ reload_transient_for (MetaWindow *window,
|
||||
if (transient_for == window->xtransient_for)
|
||||
return;
|
||||
|
||||
if (meta_window_appears_focused (window) && window->xtransient_for != None)
|
||||
meta_window_propagate_focus_appearance (window, FALSE);
|
||||
|
||||
old_transient_for = window->xtransient_for;
|
||||
window->xtransient_for = transient_for;
|
||||
|
||||
@@ -1557,46 +1566,14 @@ reload_transient_for (MetaWindow *window,
|
||||
else
|
||||
meta_verbose ("Window %s is not transient\n", window->desc);
|
||||
|
||||
/* may now be a dialog */
|
||||
meta_window_recalc_window_type (window);
|
||||
|
||||
if (!window->constructing)
|
||||
if (window->transient_parent_is_root_window || window->xtransient_for == None)
|
||||
meta_window_set_transient_for (window, NULL);
|
||||
else
|
||||
{
|
||||
/* If the window attaches, detaches, or changes attached
|
||||
* parents, we need to destroy the MetaWindow and let a new one
|
||||
* be created (which happens as a side effect of
|
||||
* meta_window_unmanage()). The condition below is correct
|
||||
* because we know window->xtransient_for has changed.
|
||||
*/
|
||||
if (window->attached || meta_window_should_attach_to_parent (window))
|
||||
{
|
||||
guint32 timestamp;
|
||||
|
||||
window->xtransient_for = old_transient_for;
|
||||
timestamp = meta_display_get_current_time_roundtrip (window->display);
|
||||
meta_window_unmanage (window, timestamp);
|
||||
return;
|
||||
}
|
||||
parent = meta_display_lookup_x_window (window->display,
|
||||
window->xtransient_for);
|
||||
meta_window_set_transient_for (window, parent);
|
||||
}
|
||||
|
||||
/* update stacking constraints */
|
||||
if (!window->override_redirect)
|
||||
meta_stack_update_transient (window->screen->stack, window);
|
||||
|
||||
/* possibly change its group. We treat being a window's transient as
|
||||
* equivalent to making it your group leader, to work around shortcomings
|
||||
* in programs such as xmms-- see #328211.
|
||||
*/
|
||||
if (window->xtransient_for != None &&
|
||||
window->xgroup_leader != None &&
|
||||
window->xtransient_for != window->xgroup_leader)
|
||||
meta_window_group_leader_changed (window);
|
||||
|
||||
if (!window->constructing && !window->override_redirect)
|
||||
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
|
||||
|
||||
if (meta_window_appears_focused (window) && window->xtransient_for != None)
|
||||
meta_window_propagate_focus_appearance (window, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1766,6 +1743,7 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
|
||||
{ display->atom__GTK_WINDOW_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_window_object_path, TRUE, FALSE },
|
||||
{ display->atom__GTK_APP_MENU_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_app_menu_object_path, TRUE, FALSE },
|
||||
{ display->atom__GTK_MENUBAR_OBJECT_PATH, META_PROP_VALUE_UTF8, reload_gtk_menubar_object_path, TRUE, FALSE },
|
||||
{ display->atom__GTK_FRAME_EXTENTS, META_PROP_VALUE_CARDINAL_LIST,reload_gtk_frame_extents, TRUE, FALSE },
|
||||
{ display->atom__NET_WM_USER_TIME_WINDOW, META_PROP_VALUE_WINDOW, reload_net_wm_user_time_window, TRUE, FALSE },
|
||||
{ display->atom_WM_STATE, META_PROP_VALUE_INVALID, NULL, FALSE, FALSE },
|
||||
{ display->atom__NET_WM_ICON, META_PROP_VALUE_INVALID, reload_net_wm_icon, FALSE, FALSE },
|
||||
|
2292
src/core/window.c
2292
src/core/window.c
File diff suppressed because it is too large
Load Diff
@@ -536,6 +536,81 @@ meta_prop_get_utf8_list (MetaDisplay *display,
|
||||
return utf8_list_from_results (&results, str_p, n_str_p);
|
||||
}
|
||||
|
||||
/* this one freakishly returns g_malloc memory */
|
||||
static gboolean
|
||||
latin1_list_from_results (GetPropertyResults *results,
|
||||
char ***str_p,
|
||||
int *n_str_p)
|
||||
{
|
||||
int i;
|
||||
int n_strings;
|
||||
char **retval;
|
||||
const char *p;
|
||||
|
||||
*str_p = NULL;
|
||||
*n_str_p = 0;
|
||||
|
||||
if (!validate_or_free_results (results, 8, XA_STRING, FALSE))
|
||||
return FALSE;
|
||||
|
||||
/* I'm not sure this is right, but I'm guessing the
|
||||
* property is nul-separated
|
||||
*/
|
||||
i = 0;
|
||||
n_strings = 0;
|
||||
while (i < (int) results->n_items)
|
||||
{
|
||||
if (results->prop[i] == '\0')
|
||||
++n_strings;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (results->prop[results->n_items - 1] != '\0')
|
||||
++n_strings;
|
||||
|
||||
/* we're guaranteed that results->prop has a nul on the end
|
||||
* by XGetWindowProperty
|
||||
*/
|
||||
|
||||
retval = g_new0 (char*, n_strings + 1);
|
||||
|
||||
p = (char *)results->prop;
|
||||
i = 0;
|
||||
while (i < n_strings)
|
||||
{
|
||||
retval[i] = g_strdup (p);
|
||||
|
||||
p = p + strlen (p) + 1;
|
||||
++i;
|
||||
}
|
||||
|
||||
*str_p = retval;
|
||||
*n_str_p = i;
|
||||
|
||||
meta_XFree (results->prop);
|
||||
results->prop = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_prop_get_latin1_list (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
Atom xatom,
|
||||
char ***str_p,
|
||||
int *n_str_p)
|
||||
{
|
||||
GetPropertyResults results;
|
||||
|
||||
*str_p = NULL;
|
||||
|
||||
if (!get_property (display, xwindow, xatom,
|
||||
XA_STRING, &results))
|
||||
return FALSE;
|
||||
|
||||
return latin1_list_from_results (&results, str_p, n_str_p);
|
||||
}
|
||||
|
||||
void
|
||||
meta_prop_set_utf8_string_hint (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
|
@@ -102,6 +102,11 @@ gboolean meta_prop_get_utf8_list (MetaDisplay *display,
|
||||
Atom xatom,
|
||||
char ***str_p,
|
||||
int *n_str_p);
|
||||
gboolean meta_prop_get_latin1_list (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
Atom xatom,
|
||||
char ***str_p,
|
||||
int *n_str_p);
|
||||
void meta_prop_set_utf8_string_hint
|
||||
(MetaDisplay *display,
|
||||
Window xwindow,
|
||||
|
35
src/idle-monitor.xml
Normal file
35
src/idle-monitor.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||
<node>
|
||||
<!--
|
||||
org.gnome.Mutter.IdleMonitor:
|
||||
@short_description: idle monitor interface
|
||||
|
||||
This interface is used by gnome-desktop to implement
|
||||
user activity monitoring.
|
||||
-->
|
||||
|
||||
<interface name="org.gnome.Mutter.IdleMonitor">
|
||||
<method name="GetIdletime">
|
||||
<arg name="idletime" direction="out" type="t"/>
|
||||
</method>
|
||||
|
||||
<method name="AddIdleWatch">
|
||||
<arg name="interval" direction="in" type="t" />
|
||||
<arg name="id" direction="out" type="u" />
|
||||
</method>
|
||||
|
||||
<method name="AddUserActiveWatch">
|
||||
<arg name="id" direction="out" type="u" />
|
||||
</method>
|
||||
|
||||
<method name="RemoveWatch">
|
||||
<arg name="id" direction="in" type="u" />
|
||||
</method>
|
||||
|
||||
<signal name="WatchFired">
|
||||
<arg name="id" direction="out" type="u" />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
18
src/libmutter-wayland.pc.in
Normal file
18
src/libmutter-wayland.pc.in
Normal file
@@ -0,0 +1,18 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
girdir=@libdir@/mutter-wayland
|
||||
typelibdir=@libdir@/mutter-wayland
|
||||
|
||||
mutter_major_version=@MUTTER_MAJOR_VERSION@
|
||||
mutter_minor_version=@MUTTER_MINOR_VERSION@
|
||||
mutter_micro_version=@MUTTER_MICRO_VERSION@
|
||||
mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@
|
||||
|
||||
Name: libmutter-wayland
|
||||
Description: Mutter window manager library (Wayland branch)
|
||||
Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11 wayland-server
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lmutter-wayland
|
||||
Cflags: -I${includedir}/mutter-wayland -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version}
|
@@ -1,18 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
girdir=@libdir@/mutter
|
||||
typelibdir=@libdir@/mutter
|
||||
|
||||
mutter_major_version=@MUTTER_MAJOR_VERSION@
|
||||
mutter_minor_version=@MUTTER_MINOR_VERSION@
|
||||
mutter_micro_version=@MUTTER_MICRO_VERSION@
|
||||
mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@
|
||||
|
||||
Name: libmutter
|
||||
Description: Mutter window manager library
|
||||
Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lmutter
|
||||
Cflags: -I${includedir}/mutter -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version}
|
@@ -54,9 +54,6 @@ item(WM_WINDOW_ROLE)
|
||||
item(UTF8_STRING)
|
||||
item(WM_ICON_SIZE)
|
||||
item(_KWM_WIN_ICON)
|
||||
item(_MUTTER_RELOAD_THEME_MESSAGE)
|
||||
item(_MUTTER_SET_KEYBINDINGS_MESSAGE)
|
||||
item(_MUTTER_TOGGLE_VERBOSE)
|
||||
item(_MUTTER_HINTS)
|
||||
item(_GTK_THEME_VARIANT)
|
||||
item(_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED)
|
||||
@@ -66,12 +63,16 @@ item(_GTK_APPLICATION_OBJECT_PATH)
|
||||
item(_GTK_WINDOW_OBJECT_PATH)
|
||||
item(_GTK_APP_MENU_OBJECT_PATH)
|
||||
item(_GTK_MENUBAR_OBJECT_PATH)
|
||||
item(_GTK_FRAME_EXTENTS)
|
||||
item(_GNOME_WM_KEYBINDINGS)
|
||||
item(_GNOME_PANEL_ACTION)
|
||||
item(_GNOME_PANEL_ACTION_MAIN_MENU)
|
||||
item(_GNOME_PANEL_ACTION_RUN_DIALOG)
|
||||
item(_MUTTER_TIMESTAMP_PING)
|
||||
item(_MUTTER_FOCUS_SET)
|
||||
item(_MUTTER_SENTINEL)
|
||||
item(_MUTTER_VERSION)
|
||||
item(_MUTTER_PRESENTATION_OUTPUT)
|
||||
item(WM_CLIENT_MACHINE)
|
||||
item(MANAGER)
|
||||
item(TARGETS)
|
||||
@@ -79,6 +80,8 @@ item(MULTIPLE)
|
||||
item(TIMESTAMP)
|
||||
item(VERSION)
|
||||
item(ATOM_PAIR)
|
||||
item(BACKLIGHT)
|
||||
item(_XKB_RULES_NAMES)
|
||||
|
||||
/* Oddities: These are used, and we need atoms for them,
|
||||
* but when we need all _NET_WM hints (i.e. when we're making
|
||||
|
@@ -35,7 +35,6 @@
|
||||
|
||||
/* Public compositor API */
|
||||
ClutterActor *meta_get_stage_for_screen (MetaScreen *screen);
|
||||
ClutterActor *meta_get_overlay_group_for_screen (MetaScreen *screen);
|
||||
Window meta_get_overlay_window (MetaScreen *screen);
|
||||
GList *meta_get_window_actors (MetaScreen *screen);
|
||||
ClutterActor *meta_get_window_group_for_screen (MetaScreen *screen);
|
||||
@@ -47,5 +46,8 @@ void meta_enable_unredirect_for_screen (MetaScreen *screen);
|
||||
void meta_set_stage_input_region (MetaScreen *screen,
|
||||
XserverRegion region);
|
||||
void meta_empty_stage_input_region (MetaScreen *screen);
|
||||
void meta_focus_stage_window (MetaScreen *screen,
|
||||
guint32 timestamp);
|
||||
gboolean meta_stage_is_focused (MetaScreen *screen);
|
||||
|
||||
#endif
|
||||
|
@@ -165,6 +165,10 @@ void meta_display_set_input_focus_window (MetaDisplay *display,
|
||||
gboolean focus_frame,
|
||||
guint32 timestamp);
|
||||
|
||||
void meta_display_request_take_focus (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
|
||||
/* meta_display_focus_the_no_focus_window is called when the
|
||||
* designated no_focus_window should be focused, but is otherwise the
|
||||
* same as meta_display_set_input_focus_window
|
||||
@@ -187,4 +191,11 @@ void meta_display_unmanage_screen (MetaDisplay *display,
|
||||
|
||||
void meta_display_clear_mouse_mode (MetaDisplay *display);
|
||||
|
||||
void meta_display_freeze_keyboard (MetaDisplay *display,
|
||||
Window window,
|
||||
guint32 timestamp);
|
||||
void meta_display_ungrab_keyboard (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
void meta_display_unfreeze_keyboard (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
#endif
|
||||
|
50
src/meta/meta-cursor-tracker.h
Normal file
50
src/meta/meta-cursor-tracker.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef META_CURSOR_TRACKER_H
|
||||
#define META_CURSOR_TRACKER_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <meta/types.h>
|
||||
#include <meta/workspace.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#define META_TYPE_CURSOR_TRACKER (meta_cursor_tracker_get_type ())
|
||||
#define META_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTracker))
|
||||
#define META_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass))
|
||||
#define META_IS_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER))
|
||||
#define META_IS_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER))
|
||||
#define META_CURSOR_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass))
|
||||
|
||||
typedef struct _MetaCursorTrackerClass MetaCursorTrackerClass;
|
||||
|
||||
GType meta_cursor_tracker_get_type (void);
|
||||
|
||||
MetaCursorTracker *meta_cursor_tracker_get_for_screen (MetaScreen *screen);
|
||||
|
||||
void meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
||||
int *x,
|
||||
int *y);
|
||||
CoglTexture *meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker);
|
||||
|
||||
#endif
|
62
src/meta/meta-idle-monitor.h
Normal file
62
src/meta/meta-idle-monitor.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_IDLE_MONITOR_H
|
||||
#define META_IDLE_MONITOR_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <meta/types.h>
|
||||
|
||||
#define META_TYPE_IDLE_MONITOR (meta_idle_monitor_get_type ())
|
||||
#define META_IDLE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR, MetaIdleMonitor))
|
||||
#define META_IDLE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR, MetaIdleMonitorClass))
|
||||
#define META_IS_IDLE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR))
|
||||
#define META_IS_IDLE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR))
|
||||
#define META_IDLE_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR, MetaIdleMonitorClass))
|
||||
|
||||
typedef struct _MetaIdleMonitor MetaIdleMonitor;
|
||||
typedef struct _MetaIdleMonitorClass MetaIdleMonitorClass;
|
||||
|
||||
GType meta_idle_monitor_get_type (void);
|
||||
|
||||
typedef void (*MetaIdleMonitorWatchFunc) (MetaIdleMonitor *monitor,
|
||||
guint watch_id,
|
||||
gpointer user_data);
|
||||
|
||||
MetaIdleMonitor *meta_idle_monitor_get_core (void);
|
||||
MetaIdleMonitor *meta_idle_monitor_get_for_device (int device_id);
|
||||
|
||||
guint meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor,
|
||||
guint64 interval_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
guint meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
void meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
|
||||
guint id);
|
||||
gint64 meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor);
|
||||
|
||||
#endif
|
@@ -205,6 +205,21 @@ struct _MetaPluginClass
|
||||
gboolean (*keybinding_filter) (MetaPlugin *plugin,
|
||||
MetaKeyBinding *binding);
|
||||
|
||||
/**
|
||||
* MetaPluginClass::confirm_display_config:
|
||||
* @plugin: a #MetaPlugin
|
||||
*
|
||||
* Virtual function called when the display configuration changes.
|
||||
* The common way to implement this function is to show some form
|
||||
* of modal dialog that should ask the user if everything was ok.
|
||||
*
|
||||
* When confirmed by the user, the plugin must call meta_plugin_complete_display_change()
|
||||
* to make the configuration permanent. If that function is not
|
||||
* called within the timeout, the previous configuration will be
|
||||
* reapplied.
|
||||
*/
|
||||
void (*confirm_display_change) (MetaPlugin *plugin);
|
||||
|
||||
/**
|
||||
* MetaPluginClass::plugin_info:
|
||||
* @plugin: a #MetaPlugin
|
||||
@@ -214,6 +229,7 @@ struct _MetaPluginClass
|
||||
* Returns: a #MetaPluginInfo.
|
||||
*/
|
||||
const MetaPluginInfo * (*plugin_info) (MetaPlugin *plugin);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -360,6 +376,10 @@ void
|
||||
meta_plugin_destroy_completed (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
|
||||
void
|
||||
meta_plugin_complete_display_change (MetaPlugin *plugin,
|
||||
gboolean ok);
|
||||
|
||||
/**
|
||||
* MetaModalOptions:
|
||||
* @META_MODAL_POINTER_ALREADY_GRABBED: if set the pointer is already
|
||||
@@ -376,8 +396,6 @@ typedef enum {
|
||||
|
||||
gboolean
|
||||
meta_plugin_begin_modal (MetaPlugin *plugin,
|
||||
Window grab_window,
|
||||
Cursor cursor,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp);
|
||||
|
||||
|
@@ -64,29 +64,29 @@ struct _MetaShapedTexture
|
||||
|
||||
GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *meta_shaped_texture_new (void);
|
||||
|
||||
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
||||
gboolean create_mipmaps);
|
||||
|
||||
void meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
|
||||
Pixmap pixmap);
|
||||
gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
cairo_region_t *unobscured_region);
|
||||
|
||||
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
|
||||
|
||||
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *mask_texture);
|
||||
void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *shape_region);
|
||||
|
||||
/* Assumes ownership of clip_region */
|
||||
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *clip_region);
|
||||
|
||||
void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *opaque_region);
|
||||
|
||||
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
||||
cairo_rectangle_int_t *clip);
|
||||
|
||||
|
@@ -64,7 +64,6 @@ gint meta_window_actor_get_workspace (MetaWindowActor *self
|
||||
MetaWindow * meta_window_actor_get_meta_window (MetaWindowActor *self);
|
||||
ClutterActor * meta_window_actor_get_texture (MetaWindowActor *self);
|
||||
gboolean meta_window_actor_is_override_redirect (MetaWindowActor *self);
|
||||
const char * meta_window_actor_get_description (MetaWindowActor *self);
|
||||
gboolean meta_window_actor_showing_on_its_workspace (MetaWindowActor *self);
|
||||
gboolean meta_window_actor_is_destroyed (MetaWindowActor *self);
|
||||
|
||||
|
@@ -49,7 +49,6 @@
|
||||
* @META_PREF_TITLEBAR_FONT: title-bar font
|
||||
* @META_PREF_NUM_WORKSPACES: number of workspaces
|
||||
* @META_PREF_DYNAMIC_WORKSPACES: dynamic workspaces
|
||||
* @META_PREF_APPLICATION_BASED: application-based
|
||||
* @META_PREF_KEYBINDINGS: keybindings
|
||||
* @META_PREF_DISABLE_WORKAROUNDS: disable workarounds
|
||||
* @META_PREF_BUTTON_LAYOUT: button layout
|
||||
@@ -88,7 +87,6 @@ typedef enum
|
||||
META_PREF_TITLEBAR_FONT,
|
||||
META_PREF_NUM_WORKSPACES,
|
||||
META_PREF_DYNAMIC_WORKSPACES,
|
||||
META_PREF_APPLICATION_BASED,
|
||||
META_PREF_KEYBINDINGS,
|
||||
META_PREF_DISABLE_WORKAROUNDS,
|
||||
META_PREF_BUTTON_LAYOUT,
|
||||
@@ -136,7 +134,6 @@ const char* meta_prefs_get_theme (void);
|
||||
const PangoFontDescription* meta_prefs_get_titlebar_font (void);
|
||||
int meta_prefs_get_num_workspaces (void);
|
||||
gboolean meta_prefs_get_dynamic_workspaces (void);
|
||||
gboolean meta_prefs_get_application_based (void);
|
||||
gboolean meta_prefs_get_disable_workarounds (void);
|
||||
gboolean meta_prefs_get_auto_raise (void);
|
||||
int meta_prefs_get_auto_raise_delay (void);
|
||||
@@ -353,6 +350,7 @@ typedef enum _MetaKeyBindingAction
|
||||
META_KEYBINDING_ACTION_MOVE_TO_SIDE_W,
|
||||
META_KEYBINDING_ACTION_MOVE_TO_CENTER,
|
||||
META_KEYBINDING_ACTION_OVERLAY_KEY,
|
||||
META_KEYBINDING_ACTION_ISO_NEXT_GROUP,
|
||||
|
||||
META_KEYBINDING_ACTION_LAST
|
||||
} MetaKeyBindingAction;
|
||||
@@ -442,6 +440,7 @@ void meta_prefs_get_window_binding (const char *name,
|
||||
MetaVirtualModifier *modifiers);
|
||||
|
||||
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
|
||||
const char *meta_prefs_get_iso_next_group_option (void);
|
||||
|
||||
gboolean meta_prefs_get_visual_bell (void);
|
||||
gboolean meta_prefs_bell_is_audible (void);
|
||||
|
@@ -1,87 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/* Metacity theme preview widget */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <meta/common.h>
|
||||
#include <meta/theme.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifndef META_PREVIEW_WIDGET_H
|
||||
#define META_PREVIEW_WIDGET_H
|
||||
|
||||
#define META_TYPE_PREVIEW (meta_preview_get_type ())
|
||||
#define META_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_PREVIEW, MetaPreview))
|
||||
#define META_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_PREVIEW, MetaPreviewClass))
|
||||
#define META_IS_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_PREVIEW))
|
||||
#define META_IS_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_PREVIEW))
|
||||
#define META_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_PREVIEW, MetaPreviewClass))
|
||||
|
||||
typedef struct _MetaPreview MetaPreview;
|
||||
typedef struct _MetaPreviewClass MetaPreviewClass;
|
||||
|
||||
struct _MetaPreview
|
||||
{
|
||||
GtkBin bin;
|
||||
|
||||
GtkStyleContext *style_context;
|
||||
|
||||
MetaTheme *theme;
|
||||
char *title;
|
||||
MetaFrameType type;
|
||||
MetaFrameFlags flags;
|
||||
|
||||
PangoLayout *layout;
|
||||
int text_height;
|
||||
|
||||
MetaFrameBorders borders;
|
||||
guint borders_cached : 1;
|
||||
|
||||
MetaButtonLayout button_layout;
|
||||
};
|
||||
|
||||
struct _MetaPreviewClass
|
||||
{
|
||||
/*< private >*/
|
||||
GtkBinClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType meta_preview_get_type (void) G_GNUC_CONST;
|
||||
GtkWidget* meta_preview_new (void);
|
||||
|
||||
void meta_preview_set_theme (MetaPreview *preview,
|
||||
MetaTheme *theme);
|
||||
void meta_preview_set_title (MetaPreview *preview,
|
||||
const char *title);
|
||||
void meta_preview_set_frame_type (MetaPreview *preview,
|
||||
MetaFrameType type);
|
||||
void meta_preview_set_frame_flags (MetaPreview *preview,
|
||||
MetaFrameFlags flags);
|
||||
void meta_preview_set_button_layout (MetaPreview *preview,
|
||||
const MetaButtonLayout *button_layout);
|
||||
|
||||
GdkPixbuf* meta_preview_get_icon (void);
|
||||
GdkPixbuf* meta_preview_get_mini_icon (void);
|
||||
|
||||
#endif
|
@@ -78,6 +78,9 @@ MetaWorkspace * meta_screen_get_active_workspace (MetaScreen *screen);
|
||||
int meta_screen_get_n_monitors (MetaScreen *screen);
|
||||
int meta_screen_get_primary_monitor (MetaScreen *screen);
|
||||
int meta_screen_get_current_monitor (MetaScreen *screen);
|
||||
int meta_screen_get_current_monitor_for_pos (MetaScreen *screen,
|
||||
int x,
|
||||
int y);
|
||||
void meta_screen_get_monitor_geometry (MetaScreen *screen,
|
||||
int monitor,
|
||||
MetaRectangle *geometry);
|
||||
|
@@ -33,8 +33,7 @@
|
||||
typedef struct _MetaTheme MetaTheme;
|
||||
|
||||
MetaTheme* meta_theme_get_current (void);
|
||||
void meta_theme_set_current (const char *name,
|
||||
gboolean force_reload);
|
||||
void meta_theme_set_current (const char *name);
|
||||
|
||||
MetaTheme* meta_theme_new (void);
|
||||
void meta_theme_free (MetaTheme *theme);
|
||||
|
@@ -38,5 +38,6 @@ typedef struct _MetaWorkspace MetaWorkspace;
|
||||
*/
|
||||
typedef struct _MetaGroup MetaGroup;
|
||||
typedef struct _MetaKeyBinding MetaKeyBinding;
|
||||
typedef struct _MetaCursorTracker MetaCursorTracker;
|
||||
|
||||
#endif
|
||||
|
@@ -37,6 +37,8 @@ void meta_set_debugging (gboolean setting);
|
||||
gboolean meta_is_syncing (void);
|
||||
void meta_set_syncing (gboolean setting);
|
||||
void meta_set_replace_current_wm (gboolean setting);
|
||||
gboolean meta_is_wayland_compositor (void);
|
||||
void meta_set_is_wayland_compositor (gboolean setting);
|
||||
|
||||
void meta_debug_spew_real (const char *format,
|
||||
...) G_GNUC_PRINTF (1, 2);
|
||||
@@ -100,7 +102,8 @@ typedef enum
|
||||
META_DEBUG_RESIZING = 1 << 18,
|
||||
META_DEBUG_SHAPES = 1 << 19,
|
||||
META_DEBUG_COMPOSITOR = 1 << 20,
|
||||
META_DEBUG_EDGE_RESISTANCE = 1 << 21
|
||||
META_DEBUG_EDGE_RESISTANCE = 1 << 21,
|
||||
META_DEBUG_DBUS = 1 << 22
|
||||
} MetaDebugTopic;
|
||||
|
||||
void meta_topic_real (MetaDebugTopic topic,
|
||||
|
@@ -81,6 +81,16 @@ typedef enum
|
||||
META_MAXIMIZE_VERTICAL = 1 << 1
|
||||
} MetaMaximizeFlags;
|
||||
|
||||
/**
|
||||
* MetaWindowClientType:
|
||||
* @META_WINDOW_CLIENT_TYPE_WAYLAND: A Wayland based window
|
||||
* @META_WINDOW_CLIENT_TYPE_X11: An X11 based window
|
||||
*/
|
||||
typedef enum {
|
||||
META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
META_WINDOW_CLIENT_TYPE_X11
|
||||
} MetaWindowClientType;
|
||||
|
||||
#define META_TYPE_WINDOW (meta_window_get_type ())
|
||||
#define META_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW, MetaWindow))
|
||||
#define META_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW, MetaWindowClass))
|
||||
@@ -237,4 +247,6 @@ void meta_window_begin_grab_op (MetaWindow *window,
|
||||
gboolean frame_action,
|
||||
guint32 timestamp);
|
||||
|
||||
gboolean meta_window_can_close (MetaWindow *window);
|
||||
|
||||
#endif
|
||||
|
@@ -1,17 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
plugindir=@MUTTER_PLUGIN_DIR@
|
||||
libgnome_serverdir=@libexecdir@
|
||||
mutter_major_version=@MUTTER_MAJOR_VERSION@
|
||||
mutter_minor_version=@MUTTER_MINOR_VERSION@
|
||||
mutter_micro_version=@MUTTER_MICRO_VERSION@
|
||||
mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@
|
||||
|
||||
Name: mutter-plugins
|
||||
Description: Dev parameters for mutter plugins
|
||||
Requires: @CLUTTER_PACKAGE@
|
||||
Version: @VERSION@
|
||||
Libs: @CLUTTER_LIBS@
|
||||
Cflags: @CLUTTER_CFLAGS@ -DWITH_CLUTTER -I${includedir}/mutter/mutter-private -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} -DMUTTER_PLUGIN_DIR=\"${plugindir}\"
|
@@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
_Name=Mutter
|
||||
Exec=mutter
|
||||
_Name=Mutter (wayland compositor)
|
||||
Exec=mutter-launch -- mutter --nested
|
||||
NoDisplay=true
|
||||
# name of loadable control center module
|
||||
X-GNOME-WMSettingsModule=metacity
|
||||
@@ -12,6 +12,5 @@ X-GnomeWMSettingsLibrary=metacity
|
||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||
X-GNOME-Bugzilla-Product=mutter
|
||||
X-GNOME-Bugzilla-Component=general
|
||||
X-GNOME-Autostart-Phase=WindowManager
|
||||
X-GNOME-Provides=windowmanager
|
||||
X-GNOME-Autostart-Phase=DisplayServer
|
||||
X-GNOME-Autostart-Notify=true
|
@@ -1,20 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
_Name=Mutter
|
||||
Exec=mutter
|
||||
# name of loadable control center module
|
||||
X-GNOME-WMSettingsModule=metacity
|
||||
# name we put on the WM spec check window
|
||||
X-GNOME-WMName=Mutter
|
||||
# back compat only
|
||||
X-GnomeWMSettingsLibrary=metacity
|
||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||
X-GNOME-Bugzilla-Product=mutter
|
||||
X-GNOME-Bugzilla-Component=general
|
||||
X-GNOME-Autostart-Phase=WindowManager
|
||||
X-GNOME-Provides=windowmanager
|
||||
X-GNOME-Autostart-Notify=true
|
||||
|
||||
[Window Manager]
|
||||
SessionManaged=true
|
||||
|
33
src/org.gnome.mutter.wayland.gschema.xml.in
Normal file
33
src/org.gnome.mutter.wayland.gschema.xml.in
Normal file
@@ -0,0 +1,33 @@
|
||||
<schemalist>
|
||||
<schema id="org.gnome.mutter.wayland.keybindings" path="/org/gnome/mutter/wayland/keybindings/"
|
||||
gettext-domain="@GETTEXT_DOMAIN@">
|
||||
<key name="switch-to-session-1" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F1']]]></default>
|
||||
<_summary>Switch to VT 1</_summary>
|
||||
</key>
|
||||
<key name="switch-to-session-2" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F2']]]></default>
|
||||
<_summary>Switch to VT 2</_summary>
|
||||
</key>
|
||||
<key name="switch-to-session-3" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F3']]]></default>
|
||||
<_summary>Switch to VT 3</_summary>
|
||||
</key>
|
||||
<key name="switch-to-session-4" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F4']]]></default>
|
||||
<_summary>Switch to VT 4</_summary>
|
||||
</key>
|
||||
<key name="switch-to-session-5" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F5']]]></default>
|
||||
<_summary>Switch to VT 5</_summary>
|
||||
</key>
|
||||
<key name="switch-to-session-6" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F6']]]></default>
|
||||
<_summary>Switch to VT 6</_summary>
|
||||
</key>
|
||||
<key name="switch-to-session-7" type="as">
|
||||
<default><![CDATA[['<Primary><Alt>F7']]]></default>
|
||||
<_summary>Switch to VT 7</_summary>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
Binary file not shown.
Before Width: | Height: | Size: 220 B |
Binary file not shown.
Before Width: | Height: | Size: 166 B |
Binary file not shown.
Before Width: | Height: | Size: 145 B |
@@ -1,8 +0,0 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
metacity-grayscale
|
||||
metacity-message
|
||||
metacity-mag
|
||||
metacity-properties
|
||||
metacity-properties.desktop
|
||||
metacity-window-demo
|
@@ -1,34 +0,0 @@
|
||||
@INTLTOOL_DESKTOP_RULE@
|
||||
|
||||
icondir=$(pkgdatadir)/icons
|
||||
icon_DATA=mutter-window-demo.png
|
||||
|
||||
INCLUDES=@MUTTER_WINDOW_DEMO_CFLAGS@ @MUTTER_MESSAGE_CFLAGS@ \
|
||||
-I$(top_srcdir)/src \
|
||||
-DMUTTER_ICON_DIR=\"$(pkgdatadir)/icons\" \
|
||||
-DMUTTER_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\"
|
||||
|
||||
mutter_message_SOURCES= \
|
||||
mutter-message.c
|
||||
|
||||
mutter_window_demo_SOURCES= \
|
||||
mutter-window-demo.c
|
||||
|
||||
mutter_mag_SOURCES= \
|
||||
mutter-mag.c
|
||||
|
||||
mutter_grayscale_SOURCES= \
|
||||
mutter-grayscale.c
|
||||
|
||||
bin_PROGRAMS=mutter-message mutter-window-demo
|
||||
|
||||
## cheesy hacks I use, don't really have any business existing. ;-)
|
||||
noinst_PROGRAMS=mutter-mag mutter-grayscale
|
||||
|
||||
mutter_message_LDADD= @MUTTER_MESSAGE_LIBS@
|
||||
mutter_window_demo_LDADD= @MUTTER_WINDOW_DEMO_LIBS@
|
||||
mutter_mag_LDADD= @MUTTER_WINDOW_DEMO_LIBS@
|
||||
mutter_grayscale_LDADD = @MUTTER_WINDOW_DEMO_LIBS@
|
||||
|
||||
EXTRA_DIST=$(icon_DATA)
|
||||
|
@@ -1,107 +0,0 @@
|
||||
/* Hack for grayscaling an image */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
|
||||
|
||||
static GdkPixbuf*
|
||||
grayscale_pixbuf (GdkPixbuf *pixbuf)
|
||||
{
|
||||
GdkPixbuf *gray;
|
||||
guchar *pixels;
|
||||
int rowstride;
|
||||
int pixstride;
|
||||
int row;
|
||||
int n_rows;
|
||||
int width;
|
||||
|
||||
gray = gdk_pixbuf_copy (pixbuf);
|
||||
rowstride = gdk_pixbuf_get_rowstride (gray);
|
||||
pixstride = gdk_pixbuf_get_has_alpha (gray) ? 4 : 3;
|
||||
|
||||
pixels = gdk_pixbuf_get_pixels (gray);
|
||||
n_rows = gdk_pixbuf_get_height (gray);
|
||||
width = gdk_pixbuf_get_width (gray);
|
||||
|
||||
row = 0;
|
||||
while (row < n_rows)
|
||||
{
|
||||
guchar *p = pixels + row * rowstride;
|
||||
guchar *end = p + (pixstride * width);
|
||||
|
||||
while (p != end)
|
||||
{
|
||||
double v = INTENSITY (p[0], p[1], p[2]);
|
||||
|
||||
p[0] = (guchar) v;
|
||||
p[1] = (guchar) v;
|
||||
p[2] = (guchar) v;
|
||||
|
||||
p += pixstride;
|
||||
}
|
||||
|
||||
++row;
|
||||
}
|
||||
|
||||
return gray;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbuf *gray;
|
||||
GError *err;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
g_printerr ("specify a single image on the command line\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = NULL;
|
||||
pixbuf = gdk_pixbuf_new_from_file (argv[1], &err);
|
||||
if (err != NULL)
|
||||
{
|
||||
g_printerr ("failed to load image: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
gray = grayscale_pixbuf (pixbuf);
|
||||
|
||||
err = NULL;
|
||||
gdk_pixbuf_save (gray, "grayscale.png", "png", &err, NULL);
|
||||
if (err != NULL)
|
||||
{
|
||||
g_printerr ("failed to save image: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_print ("wrote grayscale.png\n");
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,299 +0,0 @@
|
||||
/* Hack for use instead of xmag */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _XOPEN_SOURCE 600 /* C99 -- for rint() */
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
static GtkWidget *grab_widget = NULL;
|
||||
static GtkWidget *display_window = NULL;
|
||||
static int last_grab_x = 0;
|
||||
static int last_grab_y = 0;
|
||||
static int last_grab_width = 150;
|
||||
static int last_grab_height = 150;
|
||||
static GtkAllocation last_grab_allocation;
|
||||
static double width_factor = 4.0;
|
||||
static double height_factor = 4.0;
|
||||
static GdkInterpType interp_mode = GDK_INTERP_NEAREST;
|
||||
static guint regrab_idle_id = 0;
|
||||
|
||||
static GdkPixbuf*
|
||||
get_pixbuf (void)
|
||||
{
|
||||
GdkPixbuf *screenshot;
|
||||
GdkPixbuf *magnified;
|
||||
|
||||
#if 0
|
||||
g_print ("Size %d x %d\n",
|
||||
last_grab_width, last_grab_height);
|
||||
#endif
|
||||
|
||||
screenshot = gdk_pixbuf_get_from_window (gdk_get_default_root_window (),
|
||||
last_grab_x, last_grab_y,
|
||||
last_grab_width, last_grab_height);
|
||||
|
||||
if (screenshot == NULL)
|
||||
{
|
||||
g_printerr ("Screenshot failed\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
magnified = gdk_pixbuf_scale_simple (screenshot, last_grab_width * width_factor,
|
||||
last_grab_height * height_factor,
|
||||
interp_mode);
|
||||
|
||||
|
||||
g_object_unref (G_OBJECT (screenshot));
|
||||
|
||||
return magnified;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
regrab_idle (GtkWidget *image)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
GdkPixbuf *magnified;
|
||||
|
||||
gtk_widget_get_allocation (image, &allocation);
|
||||
|
||||
if (allocation.width != last_grab_allocation.width ||
|
||||
allocation.height != last_grab_allocation.height)
|
||||
{
|
||||
last_grab_width = rint (allocation.width / width_factor);
|
||||
last_grab_height = rint (allocation.height / height_factor);
|
||||
last_grab_allocation = allocation;
|
||||
|
||||
magnified = get_pixbuf ();
|
||||
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (image), magnified);
|
||||
|
||||
g_object_unref (G_OBJECT (magnified));
|
||||
}
|
||||
|
||||
regrab_idle_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
image_resized (GtkWidget *image)
|
||||
{
|
||||
if (regrab_idle_id == 0)
|
||||
regrab_idle_id = g_idle_add_full (G_PRIORITY_LOW + 100, (GSourceFunc) regrab_idle,
|
||||
image, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
grab_area_at_mouse (GtkWidget *invisible,
|
||||
int x_root,
|
||||
int y_root)
|
||||
{
|
||||
GdkPixbuf *magnified;
|
||||
int width, height;
|
||||
GtkWidget *widget;
|
||||
|
||||
width = last_grab_width;
|
||||
height = last_grab_height;
|
||||
|
||||
last_grab_x = x_root;
|
||||
last_grab_y = y_root;
|
||||
last_grab_width = width;
|
||||
last_grab_height = height;
|
||||
|
||||
magnified = get_pixbuf ();
|
||||
|
||||
display_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_default_size (GTK_WINDOW (display_window),
|
||||
last_grab_width, last_grab_height);
|
||||
widget = gtk_image_new_from_pixbuf (magnified);
|
||||
gtk_widget_set_size_request (widget, 40, 40);
|
||||
gtk_container_add (GTK_CONTAINER (display_window), widget);
|
||||
g_object_unref (G_OBJECT (magnified));
|
||||
|
||||
g_object_add_weak_pointer (G_OBJECT (display_window),
|
||||
(gpointer) &display_window);
|
||||
|
||||
g_signal_connect (G_OBJECT (display_window), "destroy",
|
||||
G_CALLBACK (gtk_main_quit), NULL);
|
||||
|
||||
g_signal_connect_after (G_OBJECT (widget), "size_allocate", G_CALLBACK (image_resized), NULL);
|
||||
|
||||
gtk_widget_show_all (display_window);
|
||||
}
|
||||
|
||||
static void
|
||||
shutdown_grab (void)
|
||||
{
|
||||
GdkDeviceManager *manager;
|
||||
GdkDevice *device;
|
||||
|
||||
manager = gdk_display_get_device_manager (gdk_display_get_default ());
|
||||
device = gdk_device_manager_get_client_pointer (manager);
|
||||
|
||||
gdk_device_ungrab (device, gtk_get_current_event_time ());
|
||||
gdk_device_ungrab (gdk_device_get_associated_device (device),
|
||||
gtk_get_current_event_time ());
|
||||
gtk_grab_remove (grab_widget);
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_motion (GtkWidget *invisible,
|
||||
GdkEventMotion *event,
|
||||
gpointer data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mouse_release (GtkWidget *invisible,
|
||||
GdkEventButton *event,
|
||||
gpointer data)
|
||||
{
|
||||
if (event->button != 1)
|
||||
return FALSE;
|
||||
|
||||
grab_area_at_mouse (invisible, event->x_root, event->y_root);
|
||||
|
||||
shutdown_grab ();
|
||||
|
||||
g_signal_handlers_disconnect_by_func (invisible, mouse_motion, NULL);
|
||||
g_signal_handlers_disconnect_by_func (invisible, mouse_release, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Helper Functions */
|
||||
|
||||
static gboolean mouse_press (GtkWidget *invisible,
|
||||
GdkEventButton *event,
|
||||
gpointer data);
|
||||
|
||||
static gboolean
|
||||
key_press (GtkWidget *invisible,
|
||||
GdkEventKey *event,
|
||||
gpointer data)
|
||||
{
|
||||
if (event->keyval == GDK_KEY_Escape)
|
||||
{
|
||||
shutdown_grab ();
|
||||
|
||||
g_signal_handlers_disconnect_by_func (invisible, mouse_press, NULL);
|
||||
g_signal_handlers_disconnect_by_func (invisible, key_press, NULL);
|
||||
|
||||
gtk_main_quit ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mouse_press (GtkWidget *invisible,
|
||||
GdkEventButton *event,
|
||||
gpointer data)
|
||||
{
|
||||
if (event->type == GDK_BUTTON_PRESS &&
|
||||
event->button == 1)
|
||||
{
|
||||
g_signal_connect (invisible, "motion_notify_event",
|
||||
G_CALLBACK (mouse_motion), NULL);
|
||||
g_signal_connect (invisible, "button_release_event",
|
||||
G_CALLBACK (mouse_release), NULL);
|
||||
g_signal_handlers_disconnect_by_func (invisible, mouse_press, NULL);
|
||||
g_signal_handlers_disconnect_by_func (invisible, key_press, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
begin_area_grab (void)
|
||||
{
|
||||
GdkWindow *window;
|
||||
GdkDeviceManager *manager;
|
||||
GdkDevice *device;
|
||||
|
||||
if (grab_widget == NULL)
|
||||
{
|
||||
grab_widget = gtk_invisible_new ();
|
||||
|
||||
gtk_widget_add_events (grab_widget,
|
||||
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
|
||||
|
||||
gtk_widget_show (grab_widget);
|
||||
}
|
||||
|
||||
window = gtk_widget_get_window (grab_widget);
|
||||
manager = gdk_display_get_device_manager (gdk_display_get_default ());
|
||||
device = gdk_device_manager_get_client_pointer (manager);
|
||||
|
||||
if (gdk_device_grab (device,
|
||||
window,
|
||||
GDK_OWNERSHIP_NONE,
|
||||
FALSE,
|
||||
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
|
||||
NULL,
|
||||
gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
|
||||
{
|
||||
g_warning ("Failed to grab pointer to do eyedropper");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_device_grab (gdk_device_get_associated_device (device),
|
||||
window,
|
||||
GDK_OWNERSHIP_NONE,
|
||||
FALSE,
|
||||
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
|
||||
NULL,
|
||||
gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
|
||||
{
|
||||
gdk_device_ungrab (device, gtk_get_current_event_time ());
|
||||
g_warning ("Failed to grab keyboard to do eyedropper");
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_grab_add (grab_widget);
|
||||
|
||||
g_signal_connect (grab_widget, "button_press_event",
|
||||
G_CALLBACK (mouse_press), NULL);
|
||||
g_signal_connect (grab_widget, "key_press_event",
|
||||
G_CALLBACK (key_press), NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
begin_area_grab ();
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,160 +0,0 @@
|
||||
/* Mutter send-magic-messages app */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(x) dgettext (GETTEXT_PACKAGE, x)
|
||||
#define N_(x) x
|
||||
|
||||
static Display *display;
|
||||
|
||||
static void
|
||||
send_reload_theme (void)
|
||||
{
|
||||
XEvent xev;
|
||||
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.serial = 0;
|
||||
xev.xclient.send_event = True;
|
||||
xev.xclient.display = display;
|
||||
xev.xclient.window = gdk_x11_get_default_root_xwindow ();
|
||||
xev.xclient.message_type = XInternAtom (display,
|
||||
"_MUTTER_RELOAD_THEME_MESSAGE",
|
||||
False);
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = 0;
|
||||
xev.xclient.data.l[1] = 0;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
XSendEvent (display,
|
||||
gdk_x11_get_default_root_xwindow (),
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
&xev);
|
||||
|
||||
XFlush (display);
|
||||
XSync (display, False);
|
||||
}
|
||||
|
||||
static void
|
||||
send_set_keybindings (gboolean enabled)
|
||||
{
|
||||
XEvent xev;
|
||||
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.serial = 0;
|
||||
xev.xclient.send_event = True;
|
||||
xev.xclient.display = display;
|
||||
xev.xclient.window = gdk_x11_get_default_root_xwindow ();
|
||||
xev.xclient.message_type = XInternAtom (display,
|
||||
"_MUTTER_SET_KEYBINDINGS_MESSAGE",
|
||||
False);
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = enabled;
|
||||
xev.xclient.data.l[1] = 0;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
XSendEvent (display,
|
||||
gdk_x11_get_default_root_xwindow (),
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
&xev);
|
||||
|
||||
XFlush (display);
|
||||
XSync (display, False);
|
||||
}
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static void
|
||||
send_toggle_verbose (void)
|
||||
{
|
||||
XEvent xev;
|
||||
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.serial = 0;
|
||||
xev.xclient.send_event = True;
|
||||
xev.xclient.display = display;
|
||||
xev.xclient.window = gdk_x11_get_default_root_xwindow ();
|
||||
xev.xclient.message_type = XInternAtom (display,
|
||||
"_MUTTER_TOGGLE_VERBOSE",
|
||||
False);
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = 0;
|
||||
xev.xclient.data.l[1] = 0;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
XSendEvent (display,
|
||||
gdk_x11_get_default_root_xwindow (),
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
&xev);
|
||||
|
||||
XFlush (display);
|
||||
XSync (display, False);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
g_printerr (_("Usage: %s\n"),
|
||||
"mutter-message (reload-theme|enable-keybindings|disable-keybindings|toggle-verbose)");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc < 2)
|
||||
usage ();
|
||||
|
||||
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
|
||||
if (strcmp (argv[1], "reload-theme") == 0)
|
||||
send_reload_theme ();
|
||||
else if (strcmp (argv[1], "enable-keybindings") == 0)
|
||||
send_set_keybindings (TRUE);
|
||||
else if (strcmp (argv[1], "disable-keybindings") == 0)
|
||||
send_set_keybindings (FALSE);
|
||||
else if (strcmp (argv[1], "toggle-verbose") == 0)
|
||||
{
|
||||
#ifndef WITH_VERBOSE_MODE
|
||||
g_printerr (_("Mutter was compiled without support for verbose mode\n"));
|
||||
return 1;
|
||||
#else
|
||||
send_toggle_verbose ();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
usage ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
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