Compare commits
63 Commits
wip/csd-fl
...
wip/waylan
Author | SHA1 | Date | |
---|---|---|---|
10fbaf7695 | |||
ef73402654 | |||
22cdf2d650 | |||
284b497b4c | |||
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 | |||
bfc87d13cb | |||
24564c77d6 | |||
18a21b67c2 | |||
3803fd9511 | |||
152d896f75 | |||
2f3a5f2001 | |||
0e098249b1 | |||
9a5f243f73 | |||
03f55b9485 | |||
ef9ef87d91 | |||
0ee2c21da7 | |||
9b966561c4 | |||
8c0779a9db | |||
2c901cc015 | |||
85e66f69fa | |||
a5585327dc | |||
268ebb1b18 | |||
40e820f551 | |||
f9a11b3b18 | |||
bd3c357212 | |||
b4d108dac6 | |||
6585a5760b | |||
531be6c413 | |||
f0c503b5a9 |
10
.gitignore
vendored
10
.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,10 +46,10 @@ POTFILES
|
||||
po/*.pot
|
||||
50-metacity-desktop-key.xml
|
||||
50-metacity-key.xml
|
||||
libmutter.pc
|
||||
mutter
|
||||
libmutter-wayland.pc
|
||||
mutter-wayland
|
||||
mutter-theme-viewer
|
||||
mutter.desktop
|
||||
mutter-wayland.desktop
|
||||
org.gnome.mutter.gschema.valid
|
||||
org.gnome.mutter.gschema.xml
|
||||
testasyncgetprop
|
||||
@ -74,6 +74,8 @@ 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
|
||||
doc/reference/*.args
|
||||
doc/reference/*.bak
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
SUBDIRS=src po doc
|
||||
SUBDIRS=src protocol data po doc
|
||||
|
||||
EXTRA_DIST = HACKING MAINTAINERS rationales.txt
|
||||
|
||||
|
26
NEWS
26
NEWS
@ -1,3 +1,29 @@
|
||||
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]
|
||||
|
@ -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) || {
|
||||
|
42
configure.ac
42
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], [5])
|
||||
m4_define([mutter_micro_version], [90])
|
||||
|
||||
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])
|
||||
|
||||
@ -115,6 +119,21 @@ 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
|
||||
@ -198,6 +217,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"
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||
@ -435,9 +464,10 @@ doc/man/Makefile
|
||||
doc/reference/Makefile
|
||||
doc/reference/meta-docs.sgml
|
||||
src/Makefile
|
||||
src/libmutter.pc
|
||||
src/mutter-plugins.pc
|
||||
src/libmutter-wayland.pc
|
||||
src/compositor/plugins/Makefile
|
||||
protocol/Makefile
|
||||
data/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
||||
@ -453,7 +483,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
|
||||
|
1
protocol/Makefile.am
Normal file
1
protocol/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
EXTRA_DIST = xserver.xml
|
18
protocol/xserver.xml
Normal file
18
protocol/xserver.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<protocol name="xserver">
|
||||
|
||||
<interface name="xserver" version="1">
|
||||
<request name="set_window_id">
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
<arg name="id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="client">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
|
||||
<event name="listen_socket">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
</protocol>
|
109
src/Makefile.am
109
src/Makefile.am
@ -1,7 +1,7 @@
|
||||
# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905
|
||||
.AUTOPARALLEL:
|
||||
|
||||
lib_LTLIBRARIES = libmutter.la
|
||||
lib_LTLIBRARIES = libmutter-wayland.la
|
||||
|
||||
SUBDIRS=compositor/plugins
|
||||
|
||||
@ -10,6 +10,7 @@ INCLUDES= \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
|
||||
$(MUTTER_CFLAGS) \
|
||||
-I$(top_builddir) \
|
||||
-I$(srcdir) \
|
||||
-I$(srcdir)/core \
|
||||
-I$(srcdir)/ui \
|
||||
@ -29,12 +30,21 @@ INCLUDES= \
|
||||
-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \
|
||||
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
|
||||
|
||||
mutter_built_sources = \
|
||||
$(dbus_xrandr_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/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 \
|
||||
@ -63,6 +73,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 \
|
||||
@ -113,6 +124,10 @@ 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 \
|
||||
@ -166,8 +181,24 @@ libmutter_la_SOURCES = \
|
||||
ui/ui.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
|
||||
|
||||
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
|
||||
@ -186,6 +217,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 \
|
||||
@ -203,16 +236,16 @@ libmutterinclude_base_headers = \
|
||||
libmutterinclude_extra_headers = \
|
||||
meta/atomnames.h
|
||||
|
||||
libmutterincludedir = $(includedir)/mutter/meta
|
||||
libmutterincludedir = $(includedir)/mutter-wayland/meta
|
||||
|
||||
libmutterinclude_HEADERS = \
|
||||
$(libmutterinclude_base_headers) \
|
||||
$(libmutterinclude_extra_headers)
|
||||
|
||||
bin_PROGRAMS=mutter
|
||||
bin_PROGRAMS=mutter-wayland
|
||||
|
||||
mutter_SOURCES = core/mutter.c
|
||||
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
mutter_wayland_SOURCES = core/mutter.c
|
||||
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
include $(INTROSPECTION_MAKEFILE)
|
||||
@ -234,15 +267,15 @@ 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
|
||||
@ -253,22 +286,17 @@ 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 \
|
||||
@ -276,6 +304,8 @@ xml_in_files = \
|
||||
50-mutter-windows.xml.in
|
||||
xml_DATA = $(xml_in_files:.xml.in=.xml)
|
||||
|
||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||
|
||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
|
||||
@INTLTOOL_XML_NOMERGE_RULE@
|
||||
@GSETTINGS_RULES@
|
||||
@ -284,7 +314,7 @@ convertdir = $(datadir)/GConf/gsettings
|
||||
convert_DATA = mutter-schemas.convert
|
||||
|
||||
CLEANFILES = \
|
||||
mutter.desktop \
|
||||
mutter-wayland.desktop \
|
||||
mutter-wm.desktop \
|
||||
org.gnome.mutter.gschema.xml \
|
||||
$(xml_DATA) \
|
||||
@ -294,7 +324,7 @@ CLEANFILES = \
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
pkgconfig_DATA = libmutter.pc mutter-plugins.pc
|
||||
pkgconfig_DATA = libmutter-wayland.pc
|
||||
|
||||
EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(wmproperties_files) \
|
||||
@ -304,8 +334,7 @@ EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(xml_in_files) \
|
||||
org.gnome.mutter.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
|
||||
|
||||
@ -335,8 +364,28 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
|
||||
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 \
|
||||
$(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,
|
||||
|
@ -84,6 +84,7 @@
|
||||
#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 <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
@ -172,7 +173,7 @@ process_damage (MetaCompositor *compositor,
|
||||
if (window_actor == NULL)
|
||||
return;
|
||||
|
||||
meta_window_actor_process_damage (window_actor, event);
|
||||
meta_window_actor_process_x11_damage (window_actor, event);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -327,29 +328,37 @@ void
|
||||
meta_set_stage_input_region (MetaScreen *screen,
|
||||
XserverRegion region)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
/* As a wayland compositor we can simply ignore all this trickery
|
||||
* for setting an input region on the stage for capturing events in
|
||||
* clutter since all input comes to us first and we get to choose
|
||||
* who else sees them.
|
||||
*/
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
|
||||
if (info->stage && info->output)
|
||||
{
|
||||
do_set_stage_input_region (screen, region);
|
||||
if (info->stage && info->output)
|
||||
{
|
||||
do_set_stage_input_region (screen, region);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset info->pending_input_region if one existed before and set the new
|
||||
* one to use it later. */
|
||||
if (info->pending_input_region)
|
||||
{
|
||||
XFixesDestroyRegion (xdpy, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
if (region != None)
|
||||
{
|
||||
info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
|
||||
XFixesCopyRegion (xdpy, info->pending_input_region, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset info->pending_input_region if one existed before and set the new
|
||||
* one to use it later. */
|
||||
if (info->pending_input_region)
|
||||
{
|
||||
XFixesDestroyRegion (xdpy, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
if (region != None)
|
||||
{
|
||||
info->pending_input_region = XFixesCreateRegion (xdpy, NULL, 0);
|
||||
XFixesCopyRegion (xdpy, info->pending_input_region, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -380,40 +389,44 @@ meta_focus_stage_window (MetaScreen *screen,
|
||||
if (!stage)
|
||||
return;
|
||||
|
||||
window = clutter_x11_get_stage_window (stage);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
window = clutter_x11_get_stage_window (stage);
|
||||
|
||||
if (window == None)
|
||||
return;
|
||||
if (window == None)
|
||||
return;
|
||||
|
||||
meta_display_set_input_focus_xwindow (screen->display,
|
||||
screen,
|
||||
window,
|
||||
timestamp);
|
||||
meta_display_set_input_focus_xwindow (screen->display,
|
||||
screen,
|
||||
META_FOCUS_STAGE,
|
||||
window,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_display_set_input_focus_xwindow (screen->display,
|
||||
screen,
|
||||
META_FOCUS_STAGE,
|
||||
None,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_stage_is_focused (MetaScreen *screen)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
Window window;
|
||||
|
||||
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
|
||||
if (!stage)
|
||||
return FALSE;
|
||||
|
||||
window = clutter_x11_get_stage_window (stage);
|
||||
|
||||
if (window == None)
|
||||
return FALSE;
|
||||
|
||||
return (screen->display->focus_xwindow == window);
|
||||
return (screen->display->focus_type == META_FOCUS_STAGE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
Window grab_window,
|
||||
Cursor cursor,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
{
|
||||
@ -424,10 +437,19 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
ClutterStage *stage;
|
||||
Window grab_window;
|
||||
Cursor cursor = None;
|
||||
gboolean pointer_grabbed = FALSE;
|
||||
gboolean keyboard_grabbed = FALSE;
|
||||
int result;
|
||||
|
||||
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
|
||||
if (!stage)
|
||||
return FALSE;
|
||||
|
||||
grab_window = clutter_x11_get_stage_window (stage);
|
||||
|
||||
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
|
||||
return FALSE;
|
||||
|
||||
@ -562,6 +584,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
|
||||
@ -604,6 +631,7 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xwin;
|
||||
gint width, height;
|
||||
MetaWaylandCompositor *wayland_compositor;
|
||||
|
||||
/* Check if the screen is already managed */
|
||||
if (meta_screen_get_compositor_data (screen))
|
||||
@ -616,7 +644,14 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
* We have to initialize info->pending_input_region to an empty region explicitly,
|
||||
* because None value is used to mean that the whole screen is an input region.
|
||||
*/
|
||||
info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
info->pending_input_region = XFixesCreateRegion (xdisplay, NULL, 0);
|
||||
else
|
||||
{
|
||||
/* Stage input region trickery isn't needed when we're running as a
|
||||
* wayland compositor. */
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
|
||||
info->screen = screen;
|
||||
|
||||
@ -627,7 +662,56 @@ 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;
|
||||
|
||||
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,
|
||||
@ -636,42 +720,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
|
||||
clutter_stage_set_sync_delay (CLUTTER_STAGE (info->stage), META_SYNC_DELAY);
|
||||
|
||||
meta_screen_get_size (screen, &width, &height);
|
||||
clutter_actor_realize (info->stage);
|
||||
|
||||
xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
|
||||
|
||||
XResizeWindow (xdisplay, xwin, width, height);
|
||||
|
||||
{
|
||||
long event_mask;
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
XWindowAttributes attr;
|
||||
|
||||
meta_core_add_old_event_mask (xdisplay, xwin, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_KeyPress);
|
||||
XISetMask (mask.mask, XI_KeyRelease);
|
||||
XISetMask (mask.mask, XI_ButtonPress);
|
||||
XISetMask (mask.mask, XI_ButtonRelease);
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
XISetMask (mask.mask, XI_Motion);
|
||||
XIClearMask (mask.mask, XI_TouchBegin);
|
||||
XIClearMask (mask.mask, XI_TouchEnd);
|
||||
XIClearMask (mask.mask, XI_TouchUpdate);
|
||||
XISelectEvents (xdisplay, xwin, &mask, 1);
|
||||
|
||||
event_mask = ExposureMask | PropertyChangeMask | StructureNotifyMask;
|
||||
if (XGetWindowAttributes (xdisplay, xwin, &attr))
|
||||
event_mask |= attr.your_event_mask;
|
||||
|
||||
XSelectInput (xdisplay, xwin, event_mask);
|
||||
}
|
||||
|
||||
info->window_group = meta_window_group_new (screen);
|
||||
info->top_window_group = meta_window_group_new (screen);
|
||||
|
||||
@ -680,53 +728,66 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
|
||||
info->plugin_mgr = meta_plugin_manager_new (screen);
|
||||
|
||||
/*
|
||||
* Delay the creation of the overlay window as long as we can, to avoid
|
||||
* blanking out the screen. This means that during the plugin loading, the
|
||||
* overlay window is not accessible; if the plugin needs to access it
|
||||
* directly, it should hook into the "show" signal on stage, and do
|
||||
* its stuff there.
|
||||
*/
|
||||
info->output = get_output_window (screen);
|
||||
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
|
||||
|
||||
/* Make sure there isn't any left-over output shape on the
|
||||
* overlay window by setting the whole screen to be an
|
||||
* output region.
|
||||
*
|
||||
* Note: there doesn't seem to be any real chance of that
|
||||
* because the X server will destroy the overlay window
|
||||
* when the last client using it exits.
|
||||
*/
|
||||
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
|
||||
|
||||
do_set_stage_input_region (screen, info->pending_input_region);
|
||||
if (info->pending_input_region != None)
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
XFixesDestroyRegion (xdisplay, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
/* NB: When running as a wayland compositor we don't need an X
|
||||
* composite overlay window, and we don't need to play any input
|
||||
* region tricks to redirect events into clutter. */
|
||||
info->output = None;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Delay the creation of the overlay window as long as we can, to avoid
|
||||
* blanking out the screen. This means that during the plugin loading, the
|
||||
* overlay window is not accessible; if the plugin needs to access it
|
||||
* directly, it should hook into the "show" signal on stage, and do
|
||||
* its stuff there.
|
||||
*/
|
||||
info->output = get_output_window (screen);
|
||||
XReparentWindow (xdisplay, xwin, info->output, 0, 0);
|
||||
|
||||
/* Map overlay window before redirecting windows offscreen so we catch their
|
||||
* contents until we show the stage.
|
||||
*/
|
||||
XMapWindow (xdisplay, info->output);
|
||||
/* 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);
|
||||
|
||||
redirect_windows (compositor, screen);
|
||||
do_set_stage_input_region (screen, info->pending_input_region);
|
||||
if (info->pending_input_region != None)
|
||||
{
|
||||
XFixesDestroyRegion (xdisplay, info->pending_input_region);
|
||||
info->pending_input_region = None;
|
||||
}
|
||||
|
||||
/* Map overlay window before redirecting windows offscreen so we catch their
|
||||
* contents until we show the stage.
|
||||
*/
|
||||
XMapWindow (xdisplay, info->output);
|
||||
|
||||
redirect_windows (compositor, screen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xroot = meta_screen_get_xroot (screen);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xroot = meta_screen_get_xroot (screen);
|
||||
|
||||
/* This is the most important part of cleanup - we have to do this
|
||||
* before giving up the window manager selection or the next
|
||||
* window manager won't be able to redirect subwindows */
|
||||
XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
|
||||
/* This is the most important part of cleanup - we have to do this
|
||||
* before giving up the window manager selection or the next
|
||||
* window manager won't be able to redirect subwindows */
|
||||
XCompositeUnredirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -798,15 +859,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);
|
||||
@ -993,7 +1057,8 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
if (!meta_is_wayland_compositor () &&
|
||||
event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
{
|
||||
/* Core code doesn't handle damage events, so we need to extract the MetaWindow
|
||||
* ourselves
|
||||
@ -1012,7 +1077,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
|
||||
@ -1356,20 +1421,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
|
||||
@ -1433,29 +1516,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)
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
|
@ -329,8 +329,18 @@ 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
|
||||
|
@ -267,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
|
||||
*
|
||||
@ -291,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
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_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,67 @@ 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;
|
||||
|
||||
region = cairo_region_copy (priv->clip_region);
|
||||
cairo_region_intersect (region, 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,20 +383,13 @@ 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 */
|
||||
@ -238,8 +398,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
n_rects = cairo_region_num_rectangles (priv->clip_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++)
|
||||
{
|
||||
@ -250,32 +410,23 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
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 +436,62 @@ 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;
|
||||
int n_rects;
|
||||
float *rectangles;
|
||||
int i;
|
||||
ClutterActorBox alloc;
|
||||
guint tex_width, tex_height;
|
||||
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 +541,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 +598,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 +624,142 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
void
|
||||
meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
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
|
||||
queue_damage_redraw_with_clip (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
ClutterActor *self = CLUTTER_ACTOR (stex);
|
||||
MetaShapedTexturePrivate *priv;
|
||||
ClutterActorBox allocation;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
cairo_rectangle_int_t clip;
|
||||
|
||||
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's
|
||||
* coordinate space so we need to convert from surface coordinates to
|
||||
* actor coordinates...
|
||||
*/
|
||||
|
||||
/* Calling clutter_actor_get_allocation_box() is enormously expensive
|
||||
* if the actor has an out-of-date allocation, since it triggers
|
||||
* a full redraw. clutter_actor_queue_redraw_with_clip() would redraw
|
||||
* the whole stage anyways in that case, so just go ahead and do
|
||||
* it here.
|
||||
*/
|
||||
if (!clutter_actor_has_allocation (self))
|
||||
{
|
||||
clutter_actor_queue_redraw (self);
|
||||
return;
|
||||
}
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->tex_width == 0 || priv->tex_height == 0)
|
||||
return;
|
||||
|
||||
clutter_actor_get_allocation_box (self, &allocation);
|
||||
|
||||
scale_x = (allocation.x2 - allocation.x1) / priv->tex_width;
|
||||
scale_y = (allocation.y2 - allocation.y1) / priv->tex_height;
|
||||
|
||||
clip.x = x * scale_x;
|
||||
clip.y = y * scale_y;
|
||||
clip.width = width * scale_x;
|
||||
clip.height = height * scale_y;
|
||||
clutter_actor_queue_redraw_with_clip (self, &clip);
|
||||
}
|
||||
|
||||
void
|
||||
meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
const cairo_rectangle_int_t clip = { x, y, width, height };
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return;
|
||||
|
||||
cogl_texture_pixmap_x11_update_area (priv->texture,
|
||||
x, y, width, height);
|
||||
switch (priv->type)
|
||||
{
|
||||
case META_SHAPED_TEXTURE_TYPE_X11_PIXMAP:
|
||||
cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (priv->texture),
|
||||
x, y, width, height);
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
set_cogl_texture (MetaShapedTexture *stex,
|
||||
CoglTexturePixmapX11 *cogl_tex)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
guint width, height;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture != NULL)
|
||||
cogl_object_unref (priv->texture);
|
||||
|
||||
priv->texture = cogl_tex;
|
||||
|
||||
if (priv->pipeline != NULL)
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (priv->pipeline_unshaped != NULL)
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline_unshaped, 0, COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
{
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (width != priv->tex_width ||
|
||||
height != priv->tex_height)
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* size changed to 0 going to an inavlid texture */
|
||||
priv->tex_width = 0;
|
||||
priv->tex_height = 0;
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
queue_damage_redraw_with_clip (stex, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -501,16 +777,64 @@ 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);
|
||||
|
||||
if (priv->create_mipmaps)
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower,
|
||||
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)
|
||||
{
|
||||
CoglContext *ctx =
|
||||
clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
CoglError *catch_error = NULL;
|
||||
CoglTexture *texture =
|
||||
COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
|
||||
buffer->resource,
|
||||
&catch_error));
|
||||
if (!texture)
|
||||
{
|
||||
cogl_error_free (catch_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->width = cogl_texture_get_width (texture);
|
||||
buffer->height = cogl_texture_get_height (texture);
|
||||
}
|
||||
|
||||
set_cogl_texture (stex, texture);
|
||||
}
|
||||
else
|
||||
set_cogl_texture (stex, NULL);
|
||||
@ -533,6 +857,41 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex)
|
||||
return COGL_TEXTURE (stex->priv->texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_input_shape_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
* @shape_region: the region of the texture that should respond to
|
||||
* input.
|
||||
*
|
||||
* Determines what region of the texture should accept input. For
|
||||
* X based windows this is defined by the ShapeInput region of the
|
||||
* window.
|
||||
*/
|
||||
void
|
||||
meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *shape_region)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->input_shape_region != NULL)
|
||||
{
|
||||
cairo_region_destroy (priv->input_shape_region);
|
||||
priv->input_shape_region = NULL;
|
||||
}
|
||||
|
||||
if (shape_region != NULL)
|
||||
{
|
||||
cairo_region_reference (shape_region);
|
||||
priv->input_shape_region = shape_region;
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_clip_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
@ -569,6 +928,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);
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
@ -28,10 +27,12 @@
|
||||
#include "xprops.h"
|
||||
|
||||
#include "compositor-private.h"
|
||||
#include "meta-shaped-texture-private.h"
|
||||
#include "meta-shadow-factory-private.h"
|
||||
#include "meta-window-actor-private.h"
|
||||
#include "meta-texture-rectangle.h"
|
||||
#include "region-utils.h"
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
enum {
|
||||
POSITION_CHANGED,
|
||||
@ -64,14 +65,12 @@ struct _MetaWindowActorPrivate
|
||||
MetaShadow *focused_shadow;
|
||||
MetaShadow *unfocused_shadow;
|
||||
|
||||
Pixmap back_pixmap;
|
||||
|
||||
Damage damage;
|
||||
|
||||
guint8 opacity;
|
||||
|
||||
/* A region that matches the shape of the window, including frame bounds */
|
||||
cairo_region_t *shape_region;
|
||||
/* If the window has an input shape, a region that matches the shape */
|
||||
cairo_region_t *input_region;
|
||||
/* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
|
||||
* the shape region. */
|
||||
cairo_region_t *opaque_region;
|
||||
@ -102,31 +101,41 @@ struct _MetaWindowActorPrivate
|
||||
/* List of FrameData for recent frames */
|
||||
GList *frames;
|
||||
|
||||
Pixmap back_pixmap; /* Not used in wayland compositor mode */
|
||||
Damage damage; /* Not used in wayland compositor mode */
|
||||
|
||||
guint visible : 1;
|
||||
guint mapped : 1;
|
||||
guint argb32 : 1;
|
||||
guint disposed : 1;
|
||||
guint redecorating : 1;
|
||||
|
||||
guint needs_damage_all : 1;
|
||||
guint received_damage : 1;
|
||||
guint repaint_scheduled : 1;
|
||||
|
||||
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
|
||||
* client message using the most recent frame in ->frames */
|
||||
guint needs_frame_drawn : 1;
|
||||
guint repaint_scheduled : 1;
|
||||
|
||||
guint needs_pixmap : 1;
|
||||
guint needs_reshape : 1;
|
||||
guint recompute_focused_shadow : 1;
|
||||
guint recompute_unfocused_shadow : 1;
|
||||
guint size_changed : 1;
|
||||
guint updates_frozen : 1;
|
||||
|
||||
guint needs_destroy : 1;
|
||||
|
||||
guint no_shadow : 1;
|
||||
|
||||
|
||||
/*
|
||||
* None of these are used in wayland compositor mode...
|
||||
*/
|
||||
|
||||
guint needs_damage_all : 1;
|
||||
guint received_x11_damage : 1;
|
||||
|
||||
guint needs_pixmap : 1;
|
||||
|
||||
guint x11_size_changed : 1;
|
||||
guint updates_frozen : 1;
|
||||
|
||||
guint unredirected : 1;
|
||||
|
||||
/* This is used to detect fullscreen windows that need to be unredirected */
|
||||
@ -170,7 +179,7 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
|
||||
static void meta_window_actor_detach (MetaWindowActor *self);
|
||||
static void meta_window_actor_detach_x11_pixmap (MetaWindowActor *self);
|
||||
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
|
||||
|
||||
static void meta_window_actor_handle_updates (MetaWindowActor *self);
|
||||
@ -304,18 +313,21 @@ window_decorated_notify (MetaWindow *mw,
|
||||
else
|
||||
new_xwindow = meta_window_get_xwindow (mw);
|
||||
|
||||
meta_window_actor_detach (self);
|
||||
|
||||
/*
|
||||
* First of all, clean up any resources we are currently using and will
|
||||
* be replacing.
|
||||
*/
|
||||
if (priv->damage != None)
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XDamageDestroy (xdisplay, priv->damage);
|
||||
meta_error_trap_pop (display);
|
||||
priv->damage = None;
|
||||
meta_window_actor_detach_x11_pixmap (self);
|
||||
|
||||
/*
|
||||
* First of all, clean up any resources we are currently using and will
|
||||
* be replacing.
|
||||
*/
|
||||
if (priv->damage != None)
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XDamageDestroy (xdisplay, priv->damage);
|
||||
meta_error_trap_pop (display);
|
||||
priv->damage = None;
|
||||
}
|
||||
}
|
||||
|
||||
priv->xwindow = new_xwindow;
|
||||
@ -346,8 +358,9 @@ meta_window_actor_constructed (GObject *object)
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
XRenderPictFormat *format;
|
||||
|
||||
priv->damage = XDamageCreate (xdisplay, xwindow,
|
||||
XDamageReportBoundingBox);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
priv->damage = XDamageCreate (xdisplay, xwindow,
|
||||
XDamageReportBoundingBox);
|
||||
|
||||
format = XRenderFindVisualFormat (xdisplay, window->xvisual);
|
||||
|
||||
@ -356,10 +369,16 @@ meta_window_actor_constructed (GObject *object)
|
||||
|
||||
if (!priv->actor)
|
||||
{
|
||||
priv->actor = meta_shaped_texture_new ();
|
||||
if (meta_is_wayland_compositor ())
|
||||
priv->actor = meta_shaped_texture_new_with_wayland_surface (window->surface);
|
||||
else
|
||||
priv->actor = meta_shaped_texture_new_with_xwindow (xwindow);
|
||||
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
clutter_actor_set_reactive (priv->actor, TRUE);
|
||||
|
||||
/*
|
||||
* Since we are holding a pointer to this actor independently of the
|
||||
* ClutterContainer internals, and provide a public API to access it,
|
||||
@ -385,9 +404,10 @@ meta_window_actor_constructed (GObject *object)
|
||||
|
||||
meta_window_actor_update_opacity (self);
|
||||
|
||||
/* Start off with an empty region to maintain the invariant that
|
||||
the shape region is always set */
|
||||
priv->shape_region = cairo_region_create();
|
||||
/* Start off with empty regions to maintain the invariant that
|
||||
these regions are always set */
|
||||
priv->shape_region = cairo_region_create ();
|
||||
priv->input_region = cairo_region_create ();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -406,13 +426,18 @@ meta_window_actor_dispose (GObject *object)
|
||||
priv->disposed = TRUE;
|
||||
|
||||
screen = priv->screen;
|
||||
display = meta_screen_get_display (screen);
|
||||
xdisplay = meta_display_get_xdisplay (display);
|
||||
info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
meta_window_actor_detach (self);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
display = meta_screen_get_display (screen);
|
||||
xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
meta_window_actor_detach_x11_pixmap (self);
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
||||
g_clear_pointer (&priv->input_region, cairo_region_destroy);
|
||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
|
||||
|
||||
@ -421,7 +446,7 @@ meta_window_actor_dispose (GObject *object)
|
||||
g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref);
|
||||
g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
|
||||
|
||||
if (priv->damage != None)
|
||||
if (!meta_is_wayland_compositor () && priv->damage != None)
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XDamageDestroy (xdisplay, priv->damage);
|
||||
@ -893,7 +918,8 @@ meta_window_actor_showing_on_its_workspace (MetaWindowActor *self)
|
||||
static void
|
||||
meta_window_actor_freeze (MetaWindowActor *self)
|
||||
{
|
||||
self->priv->freeze_count++;
|
||||
if (!meta_is_wayland_compositor ())
|
||||
self->priv->freeze_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -922,30 +948,33 @@ meta_window_actor_damage_all (MetaWindowActor *self)
|
||||
static void
|
||||
meta_window_actor_thaw (MetaWindowActor *self)
|
||||
{
|
||||
self->priv->freeze_count--;
|
||||
|
||||
if (G_UNLIKELY (self->priv->freeze_count < 0))
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
g_warning ("Error in freeze/thaw accounting.");
|
||||
self->priv->freeze_count = 0;
|
||||
return;
|
||||
self->priv->freeze_count--;
|
||||
|
||||
if (G_UNLIKELY (self->priv->freeze_count < 0))
|
||||
{
|
||||
g_warning ("Error in freeze/thaw accounting.");
|
||||
self->priv->freeze_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->priv->freeze_count)
|
||||
return;
|
||||
|
||||
/* We sometimes ignore moves and resizes on frozen windows */
|
||||
meta_window_actor_sync_actor_geometry (self, FALSE);
|
||||
|
||||
/* We do this now since we might be going right back into the
|
||||
* frozen state */
|
||||
meta_window_actor_handle_updates (self);
|
||||
|
||||
/* Since we ignore damage events while a window is frozen for certain effects
|
||||
* we may need to issue an update_area() covering the whole pixmap if we
|
||||
* don't know what real damage has happened. */
|
||||
if (self->priv->needs_damage_all)
|
||||
meta_window_actor_damage_all (self);
|
||||
}
|
||||
|
||||
if (self->priv->freeze_count)
|
||||
return;
|
||||
|
||||
/* We sometimes ignore moves and resizes on frozen windows */
|
||||
meta_window_actor_sync_actor_geometry (self, FALSE);
|
||||
|
||||
/* We do this now since we might be going right back into the
|
||||
* frozen state */
|
||||
meta_window_actor_handle_updates (self);
|
||||
|
||||
/* Since we ignore damage events while a window is frozen for certain effects
|
||||
* we may need to issue an update_area() covering the whole pixmap if we
|
||||
* don't know what real damage has happened. */
|
||||
if (self->priv->needs_damage_all)
|
||||
meta_window_actor_damage_all (self);
|
||||
}
|
||||
|
||||
void
|
||||
@ -976,7 +1005,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
* send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
|
||||
* consistent timing with non-empty frames.
|
||||
*/
|
||||
if (priv->mapped && !priv->needs_pixmap)
|
||||
if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
|
||||
{
|
||||
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
|
||||
clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
|
||||
@ -1002,7 +1031,7 @@ is_frozen (MetaWindowActor *self)
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_queue_create_pixmap (MetaWindowActor *self)
|
||||
meta_window_actor_queue_create_x11_pixmap (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
@ -1106,11 +1135,14 @@ meta_window_actor_after_effects (MetaWindowActor *self)
|
||||
meta_window_actor_sync_visibility (self);
|
||||
meta_window_actor_sync_actor_geometry (self, FALSE);
|
||||
|
||||
if (!meta_window_is_mapped (priv->window))
|
||||
meta_window_actor_detach (self);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
if (!meta_window_is_mapped (priv->window))
|
||||
meta_window_actor_detach_x11_pixmap (self);
|
||||
|
||||
if (priv->needs_pixmap)
|
||||
clutter_actor_queue_redraw (priv->actor);
|
||||
if (priv->needs_pixmap)
|
||||
clutter_actor_queue_redraw (priv->actor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1191,7 +1223,7 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
|
||||
* pixmap for a new size.
|
||||
*/
|
||||
static void
|
||||
meta_window_actor_detach (MetaWindowActor *self)
|
||||
meta_window_actor_detach_x11_pixmap (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaScreen *screen = priv->screen;
|
||||
@ -1212,7 +1244,7 @@ meta_window_actor_detach (MetaWindowActor *self)
|
||||
XFreePixmap (xdisplay, priv->back_pixmap);
|
||||
priv->back_pixmap = None;
|
||||
|
||||
meta_window_actor_queue_create_pixmap (self);
|
||||
meta_window_actor_queue_create_x11_pixmap (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -1227,7 +1259,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
|
||||
if (priv->opacity != 0xff)
|
||||
return FALSE;
|
||||
|
||||
if (metaWindow->has_shape)
|
||||
if (metaWindow->shape_region != NULL)
|
||||
return FALSE;
|
||||
|
||||
if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
|
||||
@ -1242,7 +1274,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
|
||||
if (meta_window_is_override_redirect (metaWindow))
|
||||
return TRUE;
|
||||
|
||||
if (priv->does_full_damage)
|
||||
if (!meta_is_wayland_compositor () && priv->does_full_damage)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
@ -1262,7 +1294,7 @@ meta_window_actor_set_redirected (MetaWindowActor *self, gboolean state)
|
||||
meta_error_trap_push (display);
|
||||
XCompositeRedirectWindow (xdisplay, xwin, CompositeRedirectManual);
|
||||
meta_error_trap_pop (display);
|
||||
meta_window_actor_detach (self);
|
||||
meta_window_actor_detach_x11_pixmap (self);
|
||||
self->priv->unredirected = FALSE;
|
||||
}
|
||||
else
|
||||
@ -1284,6 +1316,9 @@ meta_window_actor_destroy (MetaWindowActor *self)
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor), NULL);
|
||||
|
||||
window = priv->window;
|
||||
window_type = meta_window_get_window_type (window);
|
||||
meta_window_set_compositor_private (window, NULL);
|
||||
@ -1335,15 +1370,21 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
|
||||
|
||||
meta_window_get_input_rect (priv->window, &window_rect);
|
||||
|
||||
if (priv->last_width != window_rect.width ||
|
||||
priv->last_height != window_rect.height)
|
||||
/* When running as a display server then we instead catch size changes when
|
||||
* new buffers are attached */
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
priv->size_changed = TRUE;
|
||||
meta_window_actor_queue_create_pixmap (self);
|
||||
meta_window_actor_update_shape (self);
|
||||
if (priv->last_width != window_rect.width ||
|
||||
priv->last_height != window_rect.height)
|
||||
{
|
||||
priv->x11_size_changed = TRUE;
|
||||
meta_window_actor_queue_create_x11_pixmap (self);
|
||||
|
||||
priv->last_width = window_rect.width;
|
||||
priv->last_height = window_rect.height;
|
||||
meta_window_actor_update_shape (self);
|
||||
|
||||
priv->last_width = window_rect.width;
|
||||
priv->last_height = window_rect.height;
|
||||
}
|
||||
}
|
||||
|
||||
if (meta_window_actor_effect_in_progress (self))
|
||||
@ -1507,16 +1548,25 @@ meta_window_actor_new (MetaWindow *window)
|
||||
MetaWindowActor *self;
|
||||
MetaWindowActorPrivate *priv;
|
||||
MetaFrame *frame;
|
||||
Window top_window;
|
||||
Window top_window = None;
|
||||
ClutterActor *window_group;
|
||||
|
||||
frame = meta_window_get_frame (window);
|
||||
if (frame)
|
||||
top_window = meta_frame_get_xwindow (frame);
|
||||
else
|
||||
top_window = meta_window_get_xwindow (window);
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
frame = meta_window_get_frame (window);
|
||||
if (frame)
|
||||
top_window = meta_frame_get_xwindow (frame);
|
||||
else
|
||||
top_window = meta_window_get_xwindow (window);
|
||||
|
||||
meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
|
||||
meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_verbose ("add window: Meta %p, wayland surface %p\n",
|
||||
window, window->surface);
|
||||
top_window = None;
|
||||
}
|
||||
|
||||
self = g_object_new (META_TYPE_WINDOW_ACTOR,
|
||||
"meta-window", window,
|
||||
@ -1525,22 +1575,25 @@ meta_window_actor_new (MetaWindow *window)
|
||||
NULL);
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
priv->last_width = -1;
|
||||
priv->last_height = -1;
|
||||
|
||||
priv->mapped = meta_window_toplevel_is_mapped (priv->window);
|
||||
if (priv->mapped)
|
||||
meta_window_actor_queue_create_pixmap (self);
|
||||
|
||||
meta_window_actor_set_updates_frozen (self,
|
||||
meta_window_updates_are_frozen (priv->window));
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
priv->last_width = -1;
|
||||
priv->last_height = -1;
|
||||
|
||||
/* If a window doesn't start off with updates frozen, we should
|
||||
* we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
|
||||
*/
|
||||
if (priv->window->extended_sync_request_counter && !priv->updates_frozen)
|
||||
meta_window_actor_queue_frame_drawn (self, FALSE);
|
||||
if (priv->mapped)
|
||||
meta_window_actor_queue_create_x11_pixmap (self);
|
||||
|
||||
meta_window_actor_set_updates_frozen (self,
|
||||
meta_window_updates_are_frozen (priv->window));
|
||||
|
||||
/* If a window doesn't start off with updates frozen, we should
|
||||
* we should send a _NET_WM_FRAME_DRAWN immediately after the first drawn.
|
||||
*/
|
||||
if (priv->window->extended_sync_request_counter && !priv->updates_frozen)
|
||||
meta_window_actor_queue_frame_drawn (self, FALSE);
|
||||
}
|
||||
|
||||
meta_window_actor_sync_actor_geometry (self, priv->window->placed);
|
||||
|
||||
@ -1575,7 +1628,8 @@ meta_window_actor_mapped (MetaWindowActor *self)
|
||||
|
||||
priv->mapped = TRUE;
|
||||
|
||||
meta_window_actor_queue_create_pixmap (self);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
meta_window_actor_queue_create_x11_pixmap (self);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1590,8 +1644,11 @@ meta_window_actor_unmapped (MetaWindowActor *self)
|
||||
if (meta_window_actor_effect_in_progress (self))
|
||||
return;
|
||||
|
||||
meta_window_actor_detach (self);
|
||||
priv->needs_pixmap = FALSE;
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
meta_window_actor_detach_x11_pixmap (self);
|
||||
priv->needs_pixmap = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1609,10 +1666,21 @@ meta_window_actor_get_obscured_region (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
if (priv->back_pixmap && priv->opacity == 0xff && !priv->window->shaded)
|
||||
return priv->opaque_region;
|
||||
else
|
||||
return NULL;
|
||||
if (!priv->window->shaded)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
if (priv->opacity == 0xff)
|
||||
return priv->opaque_region;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->back_pixmap && priv->opacity == 0xff)
|
||||
return priv->opaque_region;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -1725,8 +1793,11 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
|
||||
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
|
||||
}
|
||||
|
||||
/* When running as a wayland compositor we don't make requests for
|
||||
* replacement pixmaps when resizing windows, we will instead be
|
||||
* asked to attach replacement buffers by the clients. */
|
||||
static void
|
||||
check_needs_pixmap (MetaWindowActor *self)
|
||||
check_needs_x11_pixmap (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaScreen *screen = priv->screen;
|
||||
@ -1748,10 +1819,10 @@ check_needs_pixmap (MetaWindowActor *self)
|
||||
|
||||
compositor = meta_display_get_compositor (display);
|
||||
|
||||
if (priv->size_changed)
|
||||
if (priv->x11_size_changed)
|
||||
{
|
||||
meta_window_actor_detach (self);
|
||||
priv->size_changed = FALSE;
|
||||
meta_window_actor_detach_x11_pixmap (self);
|
||||
priv->x11_size_changed = FALSE;
|
||||
}
|
||||
|
||||
meta_error_trap_push (display);
|
||||
@ -1883,13 +1954,13 @@ check_needs_shadow (MetaWindowActor *self)
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_process_damage (MetaWindowActor *self,
|
||||
XDamageNotifyEvent *event)
|
||||
meta_window_actor_process_x11_damage (MetaWindowActor *self,
|
||||
XDamageNotifyEvent *event)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
|
||||
|
||||
priv->received_damage = TRUE;
|
||||
priv->received_x11_damage = TRUE;
|
||||
|
||||
if (meta_window_is_fullscreen (priv->window) && g_list_last (info->windows)->data == self && !priv->unredirected)
|
||||
{
|
||||
@ -1943,6 +2014,23 @@ meta_window_actor_process_damage (MetaWindowActor *self,
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_process_wayland_damage (MetaWindowActor *self,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
if (!priv->mapped)
|
||||
return;
|
||||
|
||||
meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
|
||||
x, y, width, height);
|
||||
priv->repaint_scheduled = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_sync_visibility (MetaWindowActor *self)
|
||||
{
|
||||
@ -2083,21 +2171,35 @@ build_and_scan_frame_mask (MetaWindowActor *self,
|
||||
}
|
||||
|
||||
static void
|
||||
check_needs_reshape (MetaWindowActor *self)
|
||||
meta_window_actor_update_shape_region (MetaWindowActor *self,
|
||||
cairo_rectangle_int_t *client_area)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaScreen *screen = priv->screen;
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
MetaFrameBorders borders;
|
||||
cairo_region_t *region = NULL;
|
||||
cairo_rectangle_int_t client_area;
|
||||
gboolean needs_mask;
|
||||
|
||||
if (!priv->mapped)
|
||||
return;
|
||||
if (priv->window->frame != NULL && priv->window->shape_region != NULL)
|
||||
{
|
||||
region = cairo_region_copy (priv->window->shape_region);
|
||||
cairo_region_translate (region, client_area->x, client_area->y);
|
||||
}
|
||||
else if (priv->window->shape_region != NULL)
|
||||
{
|
||||
region = cairo_region_reference (priv->window->shape_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we don't have a shape on the server, that means that
|
||||
* we have an implicit shape of one rectangle covering the
|
||||
* entire window. */
|
||||
region = cairo_region_create_rectangle (client_area);
|
||||
}
|
||||
|
||||
if (!priv->needs_reshape)
|
||||
return;
|
||||
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
|
||||
if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL))
|
||||
build_and_scan_frame_mask (self, client_area, region);
|
||||
|
||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
||||
priv->shape_region = region;
|
||||
|
||||
if (priv->shadow_shape != NULL)
|
||||
{
|
||||
@ -2105,83 +2207,57 @@ check_needs_reshape (MetaWindowActor *self)
|
||||
priv->shadow_shape = NULL;
|
||||
}
|
||||
|
||||
meta_frame_calc_borders (priv->window->frame, &borders);
|
||||
meta_window_actor_invalidate_shadow (self);
|
||||
}
|
||||
|
||||
client_area.x = borders.total.left;
|
||||
client_area.y = borders.total.top;
|
||||
client_area.width = priv->window->rect.width;
|
||||
if (priv->window->shaded)
|
||||
client_area.height = 0;
|
||||
else
|
||||
client_area.height = priv->window->rect.height;
|
||||
static void
|
||||
meta_window_actor_update_input_region (MetaWindowActor *self,
|
||||
cairo_rectangle_int_t *client_area)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
|
||||
cairo_region_t *region = NULL;
|
||||
|
||||
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
|
||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||
|
||||
#ifdef HAVE_SHAPE
|
||||
if (priv->window->has_shape)
|
||||
if (priv->window->frame != NULL && priv->window->shape_region != NULL)
|
||||
{
|
||||
/* Translate the set of XShape rectangles that we
|
||||
* get from the X server to a cairo_region. */
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
XRectangle *rects;
|
||||
int n_rects, ordering;
|
||||
cairo_region_t *client_region = cairo_region_copy (priv->window->input_region);
|
||||
|
||||
meta_error_trap_push (display);
|
||||
rects = XShapeGetRectangles (xdisplay,
|
||||
priv->window->xwindow,
|
||||
ShapeBounding,
|
||||
&n_rects,
|
||||
&ordering);
|
||||
meta_error_trap_pop (display);
|
||||
region = meta_frame_get_frame_bounds (priv->window->frame);
|
||||
|
||||
if (rects)
|
||||
{
|
||||
int i;
|
||||
cairo_rectangle_int_t *cairo_rects = g_new (cairo_rectangle_int_t, n_rects);
|
||||
|
||||
for (i = 0; i < n_rects; i ++)
|
||||
{
|
||||
cairo_rects[i].x = rects[i].x + client_area.x;
|
||||
cairo_rects[i].y = rects[i].y + client_area.y;
|
||||
cairo_rects[i].width = rects[i].width;
|
||||
cairo_rects[i].height = rects[i].height;
|
||||
}
|
||||
|
||||
XFree (rects);
|
||||
region = cairo_region_create_rectangles (cairo_rects, n_rects);
|
||||
g_free (cairo_rects);
|
||||
}
|
||||
cairo_region_subtract_rectangle (region, client_area);
|
||||
cairo_region_translate (client_region, client_area->x, client_area->y);
|
||||
cairo_region_union (region, client_region);
|
||||
cairo_region_destroy (client_region);
|
||||
}
|
||||
#endif
|
||||
|
||||
needs_mask = (region != NULL) || (priv->window->frame != NULL);
|
||||
|
||||
if (region != NULL)
|
||||
else if (priv->window->shape_region != NULL)
|
||||
{
|
||||
/* The shape we get back from the client may have coordinates
|
||||
* outside of the frame. The X SHAPE Extension requires that
|
||||
* the overall shape the client provides never exceeds the
|
||||
* "bounding rectangle" of the window -- the shape that the
|
||||
* window would have gotten if it was unshaped. In our case,
|
||||
* this is simply the client area.
|
||||
*/
|
||||
cairo_region_intersect_rectangle (region, &client_area);
|
||||
region = cairo_region_reference (priv->window->input_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we don't have a shape on the server, that means that
|
||||
* we have an implicit shape of one rectangle covering the
|
||||
* entire window. */
|
||||
region = cairo_region_create_rectangle (&client_area);
|
||||
region = cairo_region_create_rectangle (client_area);
|
||||
}
|
||||
|
||||
/* The region at this point should be constrained to the
|
||||
* bounds of the client rectangle. */
|
||||
meta_shaped_texture_set_input_shape_region (stex, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_update_opaque_region (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||
|
||||
if (priv->argb32 && priv->window->opaque_region != NULL)
|
||||
{
|
||||
MetaFrameBorders borders;
|
||||
|
||||
meta_frame_calc_borders (priv->window->frame, &borders);
|
||||
|
||||
/* The opaque region is defined to be a part of the
|
||||
* window which ARGB32 will always paint with opaque
|
||||
* pixels. For these regions, we want to avoid painting
|
||||
@ -2193,27 +2269,46 @@ check_needs_reshape (MetaWindowActor *self)
|
||||
* case, graphical glitches will occur.
|
||||
*/
|
||||
priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
|
||||
cairo_region_translate (priv->opaque_region, client_area.x, client_area.y);
|
||||
cairo_region_intersect (priv->opaque_region, region);
|
||||
cairo_region_translate (priv->opaque_region, borders.total.left, borders.total.top);
|
||||
cairo_region_intersect (priv->opaque_region, priv->shape_region);
|
||||
}
|
||||
else if (priv->argb32)
|
||||
priv->opaque_region = NULL;
|
||||
else
|
||||
priv->opaque_region = cairo_region_reference (region);
|
||||
priv->opaque_region = cairo_region_reference (priv->shape_region);
|
||||
|
||||
if (needs_mask)
|
||||
{
|
||||
/* This takes the region, generates a mask using GTK+
|
||||
* and scans the mask looking for all opaque pixels,
|
||||
* adding it to region.
|
||||
*/
|
||||
build_and_scan_frame_mask (self, &client_area, region);
|
||||
}
|
||||
meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor),
|
||||
priv->opaque_region);
|
||||
}
|
||||
|
||||
priv->shape_region = region;
|
||||
static void
|
||||
check_needs_reshape (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaFrameBorders borders;
|
||||
cairo_rectangle_int_t client_area;
|
||||
|
||||
if (!priv->mapped)
|
||||
return;
|
||||
|
||||
if (!priv->needs_reshape)
|
||||
return;
|
||||
|
||||
meta_frame_calc_borders (priv->window->frame, &borders);
|
||||
|
||||
client_area.x = borders.total.left;
|
||||
client_area.y = borders.total.top;
|
||||
client_area.width = priv->window->rect.width;
|
||||
if (priv->window->shaded)
|
||||
client_area.height = 0;
|
||||
else
|
||||
client_area.height = priv->window->rect.height;
|
||||
|
||||
meta_window_actor_update_shape_region (self, &client_area);
|
||||
meta_window_actor_update_input_region (self, &client_area);
|
||||
meta_window_actor_update_opaque_region (self);
|
||||
|
||||
priv->needs_reshape = FALSE;
|
||||
meta_window_actor_invalidate_shadow (self);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2229,6 +2324,69 @@ meta_window_actor_update_shape (MetaWindowActor *self)
|
||||
clutter_actor_queue_redraw (priv->actor);
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_emit_size_changed (MetaWindowActor *self,
|
||||
MetaWaylandBuffer *new_buffer)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
int width = 0, height = 0;
|
||||
|
||||
if (new_buffer)
|
||||
{
|
||||
width = new_buffer->width;
|
||||
height = new_buffer->height;
|
||||
}
|
||||
|
||||
if (priv->last_width != width || priv->last_height != height)
|
||||
{
|
||||
meta_window_actor_update_shape (self);
|
||||
|
||||
/* ::size-changed is supposed to refer to meta_window_get_outer_rect()
|
||||
* but here we are only looking at buffer size changes.
|
||||
*
|
||||
* Emitting it here works pretty much OK because a new buffer size (which
|
||||
* will correspond to the outer rect with the addition of invisible
|
||||
* borders) also normally implies a change to the outer rect. In the rare
|
||||
* case where a change to the window size was exactly balanced by a
|
||||
* change to the invisible borders, we would miss emitting the signal.
|
||||
*/
|
||||
g_signal_emit (self, signals[SIZE_CHANGED], 0);
|
||||
|
||||
priv->last_width = width;
|
||||
priv->last_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_set_wayland_surface (MetaWindowActor *self,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor),
|
||||
surface);
|
||||
if (surface && surface->buffer_ref.buffer)
|
||||
maybe_emit_size_changed (self, surface->buffer_ref.buffer);
|
||||
|
||||
meta_window_actor_invalidate_shadow (self);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
|
||||
MetaWaylandBuffer *buffer)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
|
||||
CoglTexture *prev_tex = meta_shaped_texture_get_texture (stex);
|
||||
|
||||
meta_shaped_texture_attach_wayland_buffer (stex, buffer);
|
||||
|
||||
if (!prev_tex)
|
||||
meta_window_actor_sync_actor_geometry (self, FALSE);
|
||||
|
||||
maybe_emit_size_changed (self, buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_actor_handle_updates (MetaWindowActor *self)
|
||||
{
|
||||
@ -2244,42 +2402,46 @@ meta_window_actor_handle_updates (MetaWindowActor *self)
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->unredirected)
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
/* Nothing to do here until/if the window gets redirected again */
|
||||
return;
|
||||
if (priv->unredirected)
|
||||
{
|
||||
/* Nothing to do here until/if the window gets redirected again */
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->received_x11_damage)
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XDamageSubtract (xdisplay, priv->damage, None, None);
|
||||
meta_error_trap_pop (display);
|
||||
|
||||
/* We need to make sure that any X drawing that happens before the
|
||||
* XDamageSubtract() above is visible to subsequent GL rendering;
|
||||
* the only standardized way to do this is EXT_x11_sync_object,
|
||||
* which isn't yet widely available. For now, we count on details
|
||||
* of Xorg and the open source drivers, and hope for the best
|
||||
* otherwise.
|
||||
*
|
||||
* Xorg and open source driver specifics:
|
||||
*
|
||||
* The X server makes sure to flush drawing to the kernel before
|
||||
* sending out damage events, but since we use DamageReportBoundingBox
|
||||
* there may be drawing between the last damage event and the
|
||||
* XDamageSubtract() that needs to be flushed as well.
|
||||
*
|
||||
* Xorg always makes sure that drawing is flushed to the kernel
|
||||
* before writing events or responses to the client, so any round trip
|
||||
* request at this point is sufficient to flush the GLX buffers.
|
||||
*/
|
||||
XSync (xdisplay, False);
|
||||
|
||||
priv->received_x11_damage = FALSE;
|
||||
}
|
||||
|
||||
check_needs_x11_pixmap (self);
|
||||
}
|
||||
|
||||
if (priv->received_damage)
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XDamageSubtract (xdisplay, priv->damage, None, None);
|
||||
meta_error_trap_pop (display);
|
||||
|
||||
/* We need to make sure that any X drawing that happens before the
|
||||
* XDamageSubtract() above is visible to subsequent GL rendering;
|
||||
* the only standardized way to do this is EXT_x11_sync_object,
|
||||
* which isn't yet widely available. For now, we count on details
|
||||
* of Xorg and the open source drivers, and hope for the best
|
||||
* otherwise.
|
||||
*
|
||||
* Xorg and open source driver specifics:
|
||||
*
|
||||
* The X server makes sure to flush drawing to the kernel before
|
||||
* sending out damage events, but since we use DamageReportBoundingBox
|
||||
* there may be drawing between the last damage event and the
|
||||
* XDamageSubtract() that needs to be flushed as well.
|
||||
*
|
||||
* Xorg always makes sure that drawing is flushed to the kernel
|
||||
* before writing events or responses to the client, so any round trip
|
||||
* request at this point is sufficient to flush the GLX buffers.
|
||||
*/
|
||||
XSync (xdisplay, False);
|
||||
|
||||
priv->received_damage = FALSE;
|
||||
}
|
||||
|
||||
check_needs_pixmap (self);
|
||||
check_needs_reshape (self);
|
||||
check_needs_shadow (self);
|
||||
}
|
||||
@ -2458,16 +2620,20 @@ void
|
||||
meta_window_actor_set_updates_frozen (MetaWindowActor *self,
|
||||
gboolean updates_frozen)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
updates_frozen = updates_frozen != FALSE;
|
||||
|
||||
if (priv->updates_frozen != updates_frozen)
|
||||
/* On wayland we shouldn't need to ever freeze updates... */
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
priv->updates_frozen = updates_frozen;
|
||||
if (updates_frozen)
|
||||
meta_window_actor_freeze (self);
|
||||
else
|
||||
meta_window_actor_thaw (self);
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
|
||||
updates_frozen = updates_frozen != FALSE;
|
||||
|
||||
if (priv->updates_frozen != updates_frozen)
|
||||
{
|
||||
priv->updates_frozen = updates_frozen;
|
||||
if (updates_frozen)
|
||||
meta_window_actor_freeze (self);
|
||||
else
|
||||
meta_window_actor_thaw (self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "meta-window-group.h"
|
||||
#include "meta-background-actor-private.h"
|
||||
#include "meta-background-group-private.h"
|
||||
#include "window-private.h"
|
||||
|
||||
struct _MetaWindowGroupClass
|
||||
{
|
||||
@ -99,7 +100,7 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
int paint_x_offset, paint_y_offset;
|
||||
|
||||
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
|
||||
MetaCompScreen *info;
|
||||
|
||||
/* Normally we expect an actor to be drawn at it's position on the screen.
|
||||
* However, if we're inside the paint of a ClutterClone, that won't be the
|
||||
@ -136,13 +137,17 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
|
||||
visible_region = cairo_region_create_rectangle (&visible_rect);
|
||||
|
||||
if (info->unredirected_window != NULL)
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
cairo_rectangle_int_t unredirected_rect;
|
||||
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
|
||||
info = meta_screen_get_compositor_data (window_group->screen);
|
||||
if (info->unredirected_window != NULL)
|
||||
{
|
||||
cairo_rectangle_int_t unredirected_rect;
|
||||
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
|
||||
|
||||
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
|
||||
cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
|
||||
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
|
||||
cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
|
||||
}
|
||||
}
|
||||
|
||||
/* We walk the list from top to bottom (opposite of painting order),
|
||||
@ -155,7 +160,8 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
|
||||
continue;
|
||||
|
||||
if (info->unredirected_window != NULL &&
|
||||
if (!meta_is_wayland_compositor () &&
|
||||
info->unredirected_window != NULL &&
|
||||
child == CLUTTER_ACTOR (info->unredirected_window))
|
||||
continue;
|
||||
|
||||
|
@ -269,6 +269,8 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
|
||||
MetaDisplay *display;
|
||||
MetaScreen *screen;
|
||||
MetaWindow *grab_window;
|
||||
MetaStackWindow stack_window;
|
||||
MetaStackWindow stack_sibling;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_xwindow (display, xwindow);
|
||||
@ -281,9 +283,13 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
|
||||
changes.sibling = grab_window->frame ? grab_window->frame->xwindow
|
||||
: grab_window->xwindow;
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = xwindow;
|
||||
stack_sibling.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_sibling.x11.xwindow = changes.sibling;
|
||||
meta_stack_tracker_record_lower_below (screen->stack_tracker,
|
||||
xwindow,
|
||||
changes.sibling,
|
||||
&stack_window,
|
||||
&stack_sibling,
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
|
||||
meta_error_trap_push (display);
|
||||
|
@ -86,6 +86,14 @@ typedef enum {
|
||||
META_TILE_MAXIMIZED
|
||||
} MetaTileMode;
|
||||
|
||||
typedef enum {
|
||||
META_FOCUS_NONE = 0,
|
||||
META_FOCUS_X_CLIENT = 1,
|
||||
META_FOCUS_WAYLAND_CLIENT = 2,
|
||||
META_FOCUS_NO_FOCUS_WINDOW = 3,
|
||||
META_FOCUS_STAGE = 4
|
||||
} MetaFocusType;
|
||||
|
||||
struct _MetaDisplay
|
||||
{
|
||||
GObject parent_instance;
|
||||
@ -117,6 +125,7 @@ struct _MetaDisplay
|
||||
* like the no_focus_window or the stage X window. */
|
||||
Window focus_xwindow;
|
||||
gulong focus_serial;
|
||||
MetaFocusType focus_type;
|
||||
|
||||
/* last timestamp passed to XSetInputFocus */
|
||||
guint32 last_focus_time;
|
||||
@ -467,14 +476,18 @@ gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
|
||||
/* In above-tab-keycode.c */
|
||||
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
||||
|
||||
gboolean meta_display_handle_event (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
|
||||
#ifdef HAVE_XI23
|
||||
gboolean meta_display_process_barrier_event (MetaDisplay *display,
|
||||
XIBarrierEvent *event);
|
||||
#endif /* HAVE_XI23 */
|
||||
|
||||
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
Window window,
|
||||
guint32 timestamp);
|
||||
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaFocusType type,
|
||||
Window window,
|
||||
guint32 timestamp);
|
||||
|
||||
#endif
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/cursorfont.h>
|
||||
#include "mutter-enum-types.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
|
||||
#ifdef HAVE_RANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
@ -74,6 +75,8 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "meta-xwayland-private.h"
|
||||
|
||||
#define GRAB_OP_IS_WINDOW_SWITCH(g) \
|
||||
(g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \
|
||||
g == META_GRAB_OP_KEYBOARD_TABBING_DOCK || \
|
||||
@ -515,6 +518,9 @@ meta_display_open (void)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_xwayland_complete_init ();
|
||||
|
||||
if (meta_is_syncing ())
|
||||
XSynchronize (xdisplay, True);
|
||||
|
||||
@ -931,8 +937,24 @@ meta_display_open (void)
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MetaScreen *screen = tmp->data;
|
||||
|
||||
meta_screen_manage_all_windows (screen);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* Instead of explicitly enumerating all windows during
|
||||
* initialization, when we run as a wayland compositor we can rely on
|
||||
* xwayland notifying us of all top level windows so we create
|
||||
* MetaWindows when we get those notifications.
|
||||
*
|
||||
* We still want a guard window so we can avoid
|
||||
* unmapping/withdrawing minimized windows for live
|
||||
* thumbnails...
|
||||
*/
|
||||
if (screen->guard_window == None)
|
||||
screen->guard_window =
|
||||
meta_screen_create_guard_window (screen->display->xdisplay, screen);
|
||||
}
|
||||
else
|
||||
meta_screen_manage_all_windows (screen);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
@ -974,8 +996,10 @@ meta_display_open (void)
|
||||
|
||||
meta_error_trap_pop (the_display);
|
||||
}
|
||||
|
||||
meta_display_ungrab (the_display);
|
||||
|
||||
meta_idle_monitor_init_dbus ();
|
||||
|
||||
meta_display_ungrab (the_display);
|
||||
|
||||
/* Done opening new display */
|
||||
the_display->display_opening = FALSE;
|
||||
@ -1881,14 +1905,19 @@ get_input_event (MetaDisplay *display,
|
||||
}
|
||||
|
||||
static void
|
||||
update_focus_window (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
Window xwindow,
|
||||
gulong serial)
|
||||
update_focus_window (MetaDisplay *display,
|
||||
MetaFocusType type,
|
||||
MetaWindow *window,
|
||||
Window xwindow,
|
||||
gulong serial)
|
||||
{
|
||||
MetaWaylandCompositor *compositor;
|
||||
|
||||
display->focus_serial = serial;
|
||||
|
||||
if (display->focus_xwindow == xwindow)
|
||||
if (display->focus_xwindow == xwindow &&
|
||||
display->focus_type == type &&
|
||||
display->focus_window == window)
|
||||
return;
|
||||
|
||||
if (display->focus_window)
|
||||
@ -1910,6 +1939,7 @@ update_focus_window (MetaDisplay *display,
|
||||
meta_window_set_focused_internal (previous, FALSE);
|
||||
}
|
||||
|
||||
display->focus_type = type;
|
||||
display->focus_window = window;
|
||||
display->focus_xwindow = xwindow;
|
||||
|
||||
@ -1922,6 +1952,19 @@ update_focus_window (MetaDisplay *display,
|
||||
else
|
||||
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
if (display->focus_type == META_FOCUS_NO_FOCUS_WINDOW ||
|
||||
display->focus_type == META_FOCUS_STAGE)
|
||||
meta_wayland_compositor_set_input_focus (compositor, NULL);
|
||||
else if (window && window->surface)
|
||||
meta_wayland_compositor_set_input_focus (compositor, window);
|
||||
else
|
||||
meta_topic (META_DEBUG_FOCUS, "Focus change has no effect, because there is no matching wayland surface");
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (display), "focus-window");
|
||||
meta_display_update_active_window_hint (display);
|
||||
}
|
||||
@ -1956,19 +1999,18 @@ timestamp_too_old (MetaDisplay *display,
|
||||
}
|
||||
|
||||
static void
|
||||
request_xserver_input_focus_change (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
Window xwindow,
|
||||
guint32 timestamp)
|
||||
request_xserver_input_focus_change (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaFocusType type,
|
||||
MetaWindow *meta_window,
|
||||
Window xwindow,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWindow *meta_window;
|
||||
gulong serial;
|
||||
|
||||
if (timestamp_too_old (display, ×tamp))
|
||||
return;
|
||||
|
||||
meta_window = meta_display_lookup_x_window (display, xwindow);
|
||||
|
||||
meta_error_trap_push (display);
|
||||
|
||||
/* In order for mutter to know that the focus request succeeded, we track
|
||||
@ -1995,6 +2037,7 @@ request_xserver_input_focus_change (MetaDisplay *display,
|
||||
meta_display_ungrab (display);
|
||||
|
||||
update_focus_window (display,
|
||||
type,
|
||||
meta_window,
|
||||
xwindow,
|
||||
serial);
|
||||
@ -2015,9 +2058,12 @@ handle_window_focus_event (MetaDisplay *display,
|
||||
unsigned long serial)
|
||||
{
|
||||
MetaWindow *focus_window;
|
||||
MetaFocusType type;
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
const char *window_type;
|
||||
|
||||
type = META_FOCUS_NONE;
|
||||
|
||||
/* Note the event can be on either the window or the frame,
|
||||
* we focus the frame for shaded windows
|
||||
*/
|
||||
@ -2029,14 +2075,26 @@ handle_window_focus_event (MetaDisplay *display,
|
||||
window_type = "frame window";
|
||||
else
|
||||
window_type = "unknown client window";
|
||||
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
type = META_FOCUS_WAYLAND_CLIENT;
|
||||
else
|
||||
type = META_FOCUS_X_CLIENT;
|
||||
}
|
||||
else if (meta_display_xwindow_is_a_no_focus_window (display, event->event))
|
||||
window_type = "no_focus_window";
|
||||
{
|
||||
window_type = "no_focus_window";
|
||||
type = META_FOCUS_NO_FOCUS_WINDOW;
|
||||
}
|
||||
else if (meta_display_screen_for_root (display, event->event))
|
||||
window_type = "root window";
|
||||
else
|
||||
window_type = "unknown window";
|
||||
|
||||
/* Don't change type if we don't know the new window */
|
||||
if (type == META_FOCUS_NONE)
|
||||
type = display->focus_type;
|
||||
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focus %s event received on %s 0x%lx (%s) "
|
||||
"mode %s detail %s serial %lu\n",
|
||||
@ -2114,6 +2172,7 @@ handle_window_focus_event (MetaDisplay *display,
|
||||
if (display->server_focus_serial > display->focus_serial)
|
||||
{
|
||||
update_focus_window (display,
|
||||
type,
|
||||
focus_window,
|
||||
focus_window ? focus_window->xwindow : None,
|
||||
display->server_focus_serial);
|
||||
@ -2121,10 +2180,9 @@ handle_window_focus_event (MetaDisplay *display,
|
||||
}
|
||||
|
||||
/**
|
||||
* event_callback:
|
||||
* meta_display_handle_event:
|
||||
* @display: The MetaDisplay that events are coming from
|
||||
* @event: The event that just happened
|
||||
* @data: The #MetaDisplay that events are coming from, cast to a gpointer
|
||||
* so that it can be sent to a callback
|
||||
*
|
||||
* This is the most important function in the whole program. It is the heart,
|
||||
* it is the nexus, it is the Grand Central Station of Mutter's world.
|
||||
@ -2134,22 +2192,20 @@ handle_window_focus_event (MetaDisplay *display,
|
||||
* busy around here. Most of this function is a ginormous switch statement
|
||||
* dealing with all the kinds of events that might turn up.
|
||||
*/
|
||||
static gboolean
|
||||
event_callback (XEvent *event,
|
||||
gpointer data)
|
||||
gboolean
|
||||
meta_display_handle_event (MetaDisplay *display,
|
||||
XEvent *event)
|
||||
{
|
||||
MetaWindow *window;
|
||||
MetaWindow *property_for_window;
|
||||
MetaDisplay *display;
|
||||
Window modified;
|
||||
gboolean frame_was_receiver;
|
||||
gboolean bypass_compositor;
|
||||
gboolean filter_out_event;
|
||||
XIEvent *input_event;
|
||||
MetaMonitorManager *monitor;
|
||||
MetaScreen *screen;
|
||||
|
||||
display = data;
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
if (dump_events)
|
||||
meta_spew_event (display, event);
|
||||
@ -2179,11 +2235,19 @@ event_callback (XEvent *event,
|
||||
meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n",
|
||||
display->focus_window->desc);
|
||||
update_focus_window (display,
|
||||
META_FOCUS_NONE,
|
||||
meta_display_lookup_x_window (display, display->server_focus_window),
|
||||
display->server_focus_window,
|
||||
display->server_focus_serial);
|
||||
}
|
||||
|
||||
screen = meta_display_screen_for_root (display, event->xany.window);
|
||||
if (screen)
|
||||
{
|
||||
if (meta_screen_handle_xevent (screen, event))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
modified = event_get_modified_window (display, event);
|
||||
|
||||
input_event = get_input_event (display, event);
|
||||
@ -2256,6 +2320,8 @@ event_callback (XEvent *event,
|
||||
meta_window_update_sync_request_counter (alarm_window, new_counter_value);
|
||||
filter_out_event = TRUE; /* GTK doesn't want to see this really */
|
||||
}
|
||||
else
|
||||
meta_idle_monitor_handle_xevent_all (event);
|
||||
}
|
||||
#endif /* HAVE_XSYNC */
|
||||
|
||||
@ -2270,32 +2336,9 @@ event_callback (XEvent *event,
|
||||
XShapeEvent *sev = (XShapeEvent*) event;
|
||||
|
||||
if (sev->kind == ShapeBounding)
|
||||
{
|
||||
if (sev->shaped && !window->has_shape)
|
||||
{
|
||||
window->has_shape = TRUE;
|
||||
meta_topic (META_DEBUG_SHAPES,
|
||||
"Window %s now has a shape\n",
|
||||
window->desc);
|
||||
}
|
||||
else if (!sev->shaped && window->has_shape)
|
||||
{
|
||||
window->has_shape = FALSE;
|
||||
meta_topic (META_DEBUG_SHAPES,
|
||||
"Window %s no longer has a shape\n",
|
||||
window->desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_SHAPES,
|
||||
"Window %s shape changed\n",
|
||||
window->desc);
|
||||
}
|
||||
|
||||
if (display->compositor)
|
||||
meta_compositor_window_shape_changed (display->compositor,
|
||||
window);
|
||||
}
|
||||
meta_window_update_shape_region_x11 (window);
|
||||
else if (sev->kind == ShapeInput)
|
||||
meta_window_update_input_region_x11 (window);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3125,6 +3168,30 @@ event_callback (XEvent *event,
|
||||
return filter_out_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_callback (XEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
MetaDisplay *display = data;
|
||||
|
||||
/* Under Wayland we want to filter out mouse motion events so we can
|
||||
synthesize them from the Clutter events instead. This is
|
||||
necessary because the position in the mouse events is passed to
|
||||
the X server relative to the position of the surface. The X
|
||||
server then translates these back to screen coordinates based on
|
||||
the window position. If we rely on this translatation when
|
||||
dragging a window around then the window will jump around
|
||||
erratically because of the lag between updating the window
|
||||
position from the surface position. Instead we bypass the
|
||||
translation altogether by directly using the Clutter events */
|
||||
if (meta_is_wayland_compositor () &&
|
||||
event->type == GenericEvent &&
|
||||
event->xcookie.evtype == XI_Motion)
|
||||
return FALSE;
|
||||
|
||||
return meta_display_handle_event (display, event);
|
||||
}
|
||||
|
||||
/* Return the window this has to do with, if any, rather
|
||||
* than the frame or root window that was selecting
|
||||
* for substructure
|
||||
@ -5776,6 +5843,9 @@ meta_display_set_input_focus_window (MetaDisplay *display,
|
||||
{
|
||||
request_xserver_input_focus_change (display,
|
||||
window->screen,
|
||||
window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND ?
|
||||
META_FOCUS_WAYLAND_CLIENT : META_FOCUS_X_CLIENT,
|
||||
window,
|
||||
focus_frame ? window->frame->xwindow : window->xwindow,
|
||||
timestamp);
|
||||
}
|
||||
@ -5816,13 +5886,16 @@ meta_display_request_take_focus (MetaDisplay *display,
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
Window window,
|
||||
guint32 timestamp)
|
||||
meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaFocusType type,
|
||||
Window window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
request_xserver_input_focus_change (display,
|
||||
screen,
|
||||
type,
|
||||
NULL,
|
||||
window,
|
||||
timestamp);
|
||||
}
|
||||
@ -5834,6 +5907,8 @@ meta_display_focus_the_no_focus_window (MetaDisplay *display,
|
||||
{
|
||||
request_xserver_input_focus_change (display,
|
||||
screen,
|
||||
META_FOCUS_NO_FOCUS_WINDOW,
|
||||
NULL,
|
||||
screen->no_focus_window,
|
||||
timestamp);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
XSetWindowAttributes attrs;
|
||||
Visual *visual;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame)
|
||||
return;
|
||||
@ -105,8 +106,10 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
frame->rect.height,
|
||||
frame->window->screen->number,
|
||||
&create_serial);
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = frame->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
frame->xwindow,
|
||||
&stack_window,
|
||||
create_serial);
|
||||
|
||||
meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
|
||||
@ -138,8 +141,9 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
window->rect.x = 0;
|
||||
window->rect.y = 0;
|
||||
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_remove (window->screen->stack_tracker,
|
||||
window->xwindow,
|
||||
&stack_window,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
@ -174,6 +178,7 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
{
|
||||
MetaFrame *frame;
|
||||
MetaFrameBorders borders;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame == NULL)
|
||||
return;
|
||||
@ -200,8 +205,10 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
|
||||
window->unmaps_pending += 1;
|
||||
}
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
window->xwindow,
|
||||
&stack_window,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "session.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/compositor.h>
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gdk/gdkx.h>
|
||||
@ -346,28 +347,64 @@ meta_finalize (void)
|
||||
if (display)
|
||||
meta_display_close (display,
|
||||
CurrentTime); /* I doubt correct timestamps matter here */
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_wayland_finalize ();
|
||||
}
|
||||
|
||||
static int sigterm_pipe_fds[2] = { -1, -1 };
|
||||
static int signal_pipe_fds[2] = { -1, -1 };
|
||||
|
||||
static void
|
||||
sigterm_handler (int signum)
|
||||
signal_handler (int signum)
|
||||
{
|
||||
if (sigterm_pipe_fds[1] >= 0)
|
||||
if (signal_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;
|
||||
switch (signum)
|
||||
{
|
||||
case SIGTERM:
|
||||
write (signal_pipe_fds[1], "T", 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_sigterm (void)
|
||||
on_signal (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
void *data)
|
||||
{
|
||||
meta_quit (META_EXIT_SUCCESS);
|
||||
return FALSE;
|
||||
char signal;
|
||||
int count;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count = read (signal_pipe_fds[0], &signal, 1);
|
||||
if (count == EINTR)
|
||||
continue;
|
||||
if (count < 0)
|
||||
{
|
||||
const char *msg = strerror (errno);
|
||||
g_warning ("Error handling signal: %s", msg);
|
||||
}
|
||||
if (count != 1)
|
||||
{
|
||||
g_warning ("Unexpectedly failed to read byte from signal pipe\n");
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (signal)
|
||||
{
|
||||
case 'T': /* SIGTERM */
|
||||
meta_quit (META_EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
g_warning ("Spurious character '%c' read from signal pipe", signal);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -396,17 +433,17 @@ meta_init (void)
|
||||
g_strerror (errno));
|
||||
#endif
|
||||
|
||||
if (pipe (sigterm_pipe_fds) != 0)
|
||||
g_printerr ("Failed to create SIGTERM pipe: %s\n",
|
||||
if (pipe (signal_pipe_fds) != 0)
|
||||
g_printerr ("Failed to create signal pipe: %s\n",
|
||||
g_strerror (errno));
|
||||
|
||||
channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
|
||||
channel = g_io_channel_unix_new (signal_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_add_watch (channel, G_IO_IN, (GIOFunc) on_signal, NULL);
|
||||
g_io_channel_set_close_on_unref (channel, TRUE);
|
||||
g_io_channel_unref (channel);
|
||||
|
||||
act.sa_handler = &sigterm_handler;
|
||||
act.sa_handler = &signal_handler;
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||
g_printerr ("Failed to register SIGTERM handler: %s\n",
|
||||
g_strerror (errno));
|
||||
@ -427,9 +464,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 +485,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 ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
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);
|
||||
}
|
||||
|
@ -337,18 +337,23 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
dpms_enabled)
|
||||
{
|
||||
switch (dpms_state)
|
||||
{
|
||||
case DPMSModeOn:
|
||||
manager->power_save_mode = META_POWER_SAVE_ON;
|
||||
case DPMSModeStandby:
|
||||
manager->power_save_mode = META_POWER_SAVE_STANDBY;
|
||||
case DPMSModeSuspend:
|
||||
manager->power_save_mode = META_POWER_SAVE_SUSPEND;
|
||||
case DPMSModeOff:
|
||||
manager->power_save_mode = META_POWER_SAVE_OFF;
|
||||
default:
|
||||
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
|
||||
}
|
||||
{
|
||||
case DPMSModeOn:
|
||||
manager->power_save_mode = META_POWER_SAVE_ON;
|
||||
break;
|
||||
case DPMSModeStandby:
|
||||
manager->power_save_mode = META_POWER_SAVE_STANDBY;
|
||||
break;
|
||||
case DPMSModeSuspend:
|
||||
manager->power_save_mode = META_POWER_SAVE_SUSPEND;
|
||||
break;
|
||||
case DPMSModeOff:
|
||||
manager->power_save_mode = META_POWER_SAVE_OFF;
|
||||
break;
|
||||
default:
|
||||
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -527,7 +532,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
|
||||
*/
|
||||
for (j = 0; j < (unsigned)output->nclone; j++)
|
||||
{
|
||||
meta_output->possible_clones = GINT_TO_POINTER (output->clones[j]);
|
||||
meta_output->possible_clones[j] = GINT_TO_POINTER (output->clones[j]);
|
||||
}
|
||||
|
||||
meta_output->is_primary = ((XID)meta_output->output_id == primary_output);
|
||||
@ -772,17 +777,51 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
{
|
||||
MetaMonitorMode *mode;
|
||||
XID *outputs;
|
||||
int j, n_outputs;
|
||||
unsigned int j, n_outputs;
|
||||
int width, height;
|
||||
Status ok;
|
||||
unsigned long old_controlled_mask;
|
||||
unsigned long new_controlled_mask;
|
||||
|
||||
mode = crtc_info->mode;
|
||||
|
||||
n_outputs = crtc_info->outputs->len;
|
||||
outputs = g_new (XID, n_outputs);
|
||||
|
||||
old_controlled_mask = 0;
|
||||
for (j = 0; j < manager->n_outputs; j++)
|
||||
{
|
||||
MetaOutput *output;
|
||||
|
||||
output = &manager->outputs[j];
|
||||
|
||||
if (output->crtc == crtc)
|
||||
old_controlled_mask |= 1UL << j;
|
||||
}
|
||||
|
||||
new_controlled_mask = 0;
|
||||
for (j = 0; j < n_outputs; j++)
|
||||
outputs[j] = ((MetaOutput**)crtc_info->outputs->pdata)[j]->output_id;
|
||||
{
|
||||
MetaOutput *output;
|
||||
|
||||
output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
new_controlled_mask |= 1UL << j;
|
||||
|
||||
outputs[j] = output->output_id;
|
||||
}
|
||||
|
||||
if (crtc->current_mode == mode &&
|
||||
crtc->rect.x == crtc_info->x &&
|
||||
crtc->rect.y == crtc_info->y &&
|
||||
crtc->transform == crtc_info->transform &&
|
||||
old_controlled_mask == new_controlled_mask)
|
||||
{
|
||||
/* No change */
|
||||
goto next;
|
||||
}
|
||||
|
||||
meta_error_trap_push (meta_get_display ());
|
||||
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
|
||||
@ -801,11 +840,9 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
(unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id),
|
||||
mode->width, mode->height, (float)mode->refresh_rate,
|
||||
crtc_info->x, crtc_info->y, crtc_info->transform);
|
||||
continue;
|
||||
goto next;
|
||||
}
|
||||
|
||||
g_free (outputs);
|
||||
|
||||
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
||||
{
|
||||
width = mode->height;
|
||||
@ -824,15 +861,8 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
|
||||
crtc->current_mode = mode;
|
||||
crtc->transform = crtc_info->transform;
|
||||
|
||||
for (j = 0; j < n_outputs; j++)
|
||||
{
|
||||
MetaOutput *output;
|
||||
|
||||
output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
}
|
||||
next:
|
||||
g_free (outputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,6 @@
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
enum {
|
||||
MONITORS_CHANGED,
|
||||
CONFIRM_DISPLAY_CHANGE,
|
||||
SIGNALS_LAST
|
||||
};
|
||||
@ -475,6 +474,15 @@ make_logical_config (MetaMonitorManager *manager)
|
||||
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
|
||||
}
|
||||
|
||||
static GType
|
||||
get_default_backend (void)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
return META_TYPE_MONITOR_MANAGER; /* FIXME: KMS */
|
||||
else
|
||||
return META_TYPE_MONITOR_MANAGER_XRANDR;
|
||||
}
|
||||
|
||||
static MetaMonitorManager *
|
||||
meta_monitor_manager_new (void)
|
||||
{
|
||||
@ -484,7 +492,7 @@ meta_monitor_manager_new (void)
|
||||
env = g_getenv ("META_DEBUG_MULTIMONITOR");
|
||||
|
||||
if (env == NULL)
|
||||
type = META_TYPE_MONITOR_MANAGER_XRANDR;
|
||||
type = get_default_backend ();
|
||||
else if (strcmp (env, "xrandr") == 0)
|
||||
type = META_TYPE_MONITOR_MANAGER_XRANDR;
|
||||
else
|
||||
@ -660,14 +668,6 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
|
||||
klass->get_edid_file = get_edid_file_dummy;
|
||||
klass->read_edid = read_edid_dummy;
|
||||
|
||||
signals[MONITORS_CHANGED] =
|
||||
g_signal_new ("monitors-changed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
signals[CONFIRM_DISPLAY_CHANGE] =
|
||||
g_signal_new ("confirm-display-change",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
@ -813,6 +813,10 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
||||
g_variant_new_string (output->product));
|
||||
g_variant_builder_add (&properties, "{sv}", "serial",
|
||||
g_variant_new_string (output->serial));
|
||||
g_variant_builder_add (&properties, "{sv}", "width-mm",
|
||||
g_variant_new_int32 (output->width_mm));
|
||||
g_variant_builder_add (&properties, "{sv}", "height-mm",
|
||||
g_variant_new_int32 (output->height_mm));
|
||||
g_variant_builder_add (&properties, "{sv}", "display-name",
|
||||
g_variant_new_take_string (make_display_name (manager, output)));
|
||||
g_variant_builder_add (&properties, "{sv}", "backlight",
|
||||
@ -1233,7 +1237,7 @@ meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
|
||||
|
||||
META_MONITOR_MANAGER_GET_CLASS (manager)->change_backlight (manager, output, value);
|
||||
|
||||
meta_dbus_display_config_complete_change_backlight (skeleton, invocation);
|
||||
meta_dbus_display_config_complete_change_backlight (skeleton, invocation, output->backlight);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -1493,7 +1497,7 @@ invalidate_logical_config (MetaMonitorManager *manager)
|
||||
|
||||
make_logical_config (manager);
|
||||
|
||||
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
|
||||
g_signal_emit_by_name (manager, "monitors-changed");
|
||||
|
||||
g_free (old_monitor_infos);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -83,6 +83,7 @@ struct _MetaScreen
|
||||
MetaStack *stack;
|
||||
MetaStackTracker *stack_tracker;
|
||||
|
||||
MetaCursorTracker *cursor_tracker;
|
||||
MetaCursor current_cursor;
|
||||
|
||||
Window flash_window;
|
||||
@ -244,6 +245,11 @@ 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,
|
||||
|
@ -45,6 +45,8 @@
|
||||
#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>
|
||||
|
||||
@ -445,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;
|
||||
@ -483,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);
|
||||
@ -669,8 +674,9 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->xscreen = ScreenOfDisplay (xdisplay, number);
|
||||
screen->xroot = xroot;
|
||||
screen->rect.x = screen->rect.y = 0;
|
||||
|
||||
meta_monitor_manager_initialize ();
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
meta_monitor_manager_initialize ();
|
||||
|
||||
manager = meta_monitor_manager_get ();
|
||||
g_signal_connect (manager, "monitors-changed",
|
||||
@ -705,7 +711,8 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->guard_window = None;
|
||||
|
||||
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 */
|
||||
@ -930,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);
|
||||
|
||||
@ -1461,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
|
||||
@ -1746,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);
|
||||
}
|
||||
|
||||
@ -3688,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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,36 +37,55 @@
|
||||
#define META_STACK_TRACKER_H
|
||||
|
||||
#include <meta/screen.h>
|
||||
#include <meta/window.h>
|
||||
|
||||
typedef struct _MetaStackTracker MetaStackTracker;
|
||||
|
||||
typedef union _MetaStackWindow
|
||||
{
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
} any;
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
Window xwindow;
|
||||
} x11;
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
MetaWindow *meta_window;
|
||||
} wayland;
|
||||
} MetaStackWindow;
|
||||
|
||||
gboolean meta_stack_window_equal (const MetaStackWindow *a,
|
||||
const MetaStackWindow *b);
|
||||
|
||||
MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen);
|
||||
void meta_stack_tracker_free (MetaStackTracker *tracker);
|
||||
|
||||
/* These functions are called when we make an X call that changes the
|
||||
* stacking order; this allows MetaStackTracker to predict stacking
|
||||
* order before it receives events back from the X server */
|
||||
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
|
||||
Window *windows,
|
||||
int n_windows,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
Window sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
Window sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *windows,
|
||||
int n_windows,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
const MetaStackWindow *sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
const MetaStackWindow *sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
|
||||
/* These functions are used to update the stack when we get events
|
||||
* reflecting changes to the stacking order */
|
||||
@ -79,9 +98,9 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker,
|
||||
void meta_stack_tracker_configure_event (MetaStackTracker *tracker,
|
||||
XConfigureEvent *event);
|
||||
|
||||
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
|
||||
Window **windows,
|
||||
int *n_windows);
|
||||
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
|
||||
MetaStackWindow **windows,
|
||||
int *n_entries);
|
||||
|
||||
void meta_stack_tracker_sync_stack (MetaStackTracker *tracker);
|
||||
void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);
|
||||
|
534
src/core/stack.c
534
src/core/stack.c
@ -52,7 +52,7 @@
|
||||
|
||||
#define WINDOW_IN_STACK(w) (w->stack_position >= 0)
|
||||
|
||||
static void stack_sync_to_server (MetaStack *stack);
|
||||
static void stack_sync_to_xserver (MetaStack *stack);
|
||||
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
|
||||
int position);
|
||||
static void stack_do_window_deletions (MetaStack *stack);
|
||||
@ -71,14 +71,14 @@ meta_stack_new (MetaScreen *screen)
|
||||
stack = g_new (MetaStack, 1);
|
||||
|
||||
stack->screen = screen;
|
||||
stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
stack->sorted = NULL;
|
||||
stack->added = NULL;
|
||||
stack->removed = NULL;
|
||||
|
||||
stack->freeze_count = 0;
|
||||
stack->last_root_children_stacked = NULL;
|
||||
stack->last_all_root_children_stacked = NULL;
|
||||
|
||||
stack->n_positions = 0;
|
||||
|
||||
@ -89,17 +89,34 @@ meta_stack_new (MetaScreen *screen)
|
||||
return stack;
|
||||
}
|
||||
|
||||
static void
|
||||
free_last_all_root_children_stacked_cache (MetaStack *stack)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < stack->last_all_root_children_stacked->len; i++)
|
||||
{
|
||||
MetaStackWindow *window = &g_array_index (stack->last_all_root_children_stacked, MetaStackWindow, i);
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
g_object_remove_weak_pointer (G_OBJECT (window->wayland.meta_window),
|
||||
(gpointer *)&window->wayland.meta_window);
|
||||
}
|
||||
|
||||
g_array_free (stack->last_all_root_children_stacked, TRUE);
|
||||
stack->last_all_root_children_stacked = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_stack_free (MetaStack *stack)
|
||||
{
|
||||
g_array_free (stack->windows, TRUE);
|
||||
g_array_free (stack->xwindows, TRUE);
|
||||
|
||||
g_list_free (stack->sorted);
|
||||
g_list_free (stack->added);
|
||||
g_list_free (stack->removed);
|
||||
|
||||
if (stack->last_root_children_stacked)
|
||||
g_array_free (stack->last_root_children_stacked, TRUE);
|
||||
if (stack->last_all_root_children_stacked)
|
||||
free_last_all_root_children_stacked_cache (stack);
|
||||
|
||||
g_free (stack);
|
||||
}
|
||||
@ -121,7 +138,7 @@ meta_stack_add (MetaStack *stack,
|
||||
"Window %s has stack_position initialized to %d\n",
|
||||
window->desc, window->stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -157,7 +174,7 @@ meta_stack_remove (MetaStack *stack,
|
||||
stack->removed = g_list_prepend (stack->removed,
|
||||
GUINT_TO_POINTER (window->frame->xwindow));
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -167,7 +184,7 @@ meta_stack_update_layer (MetaStack *stack,
|
||||
{
|
||||
stack->need_relayer = TRUE;
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -177,7 +194,7 @@ meta_stack_update_transient (MetaStack *stack,
|
||||
{
|
||||
stack->need_constrain = TRUE;
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -206,7 +223,7 @@ meta_stack_raise (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, max_stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -234,7 +251,7 @@ meta_stack_lower (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, min_stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -250,7 +267,7 @@ meta_stack_thaw (MetaStack *stack)
|
||||
g_return_if_fail (stack->freeze_count > 0);
|
||||
|
||||
stack->freeze_count -= 1;
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@ -829,7 +846,7 @@ stack_do_window_deletions (MetaStack *stack)
|
||||
/* We go from the end figuring removals are more
|
||||
* likely to be recent.
|
||||
*/
|
||||
i = stack->windows->len;
|
||||
i = stack->xwindows->len;
|
||||
while (i > 0)
|
||||
{
|
||||
--i;
|
||||
@ -840,9 +857,9 @@ stack_do_window_deletions (MetaStack *stack)
|
||||
* both the window->xwindow and window->frame->xwindow
|
||||
* in the removal list.
|
||||
*/
|
||||
if (xwindow == g_array_index (stack->windows, Window, i))
|
||||
if (xwindow == g_array_index (stack->xwindows, Window, i))
|
||||
{
|
||||
g_array_remove_index (stack->windows, i);
|
||||
g_array_remove_index (stack->xwindows, i);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
@ -871,10 +888,10 @@ stack_do_window_additions (MetaStack *stack)
|
||||
"Adding %d windows to sorted list\n",
|
||||
n_added);
|
||||
|
||||
old_size = stack->windows->len;
|
||||
g_array_set_size (stack->windows, old_size + n_added);
|
||||
old_size = stack->xwindows->len;
|
||||
g_array_set_size (stack->xwindows, old_size + n_added);
|
||||
|
||||
end = &g_array_index (stack->windows, Window, old_size);
|
||||
end = &g_array_index (stack->xwindows, Window, old_size);
|
||||
|
||||
/* stack->added has the most recent additions at the
|
||||
* front of the list, so we need to reverse it
|
||||
@ -1029,6 +1046,102 @@ stack_ensure_sorted (MetaStack *stack)
|
||||
stack_do_resort (stack);
|
||||
}
|
||||
|
||||
static MetaStackWindow *
|
||||
find_top_most_managed_window (MetaScreen *screen,
|
||||
const MetaStackWindow *ignore)
|
||||
{
|
||||
MetaStackTracker *stack_tracker = screen->stack_tracker;
|
||||
MetaStackWindow *windows;
|
||||
int n_windows;
|
||||
int i;
|
||||
|
||||
meta_stack_tracker_get_stack (stack_tracker,
|
||||
&windows, &n_windows);
|
||||
|
||||
/* Children are in order from bottom to top. We want to
|
||||
* find the topmost managed child, then configure
|
||||
* our window to be above it.
|
||||
*/
|
||||
for (i = n_windows -1; i >= 0; i--)
|
||||
{
|
||||
MetaStackWindow *other_window = &windows[i];
|
||||
|
||||
if (other_window->any.type == ignore->any.type &&
|
||||
((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
other_window->x11.xwindow == ignore->x11.xwindow) ||
|
||||
other_window->wayland.meta_window == ignore->wayland.meta_window))
|
||||
{
|
||||
/* Do nothing. This means we're already the topmost managed
|
||||
* window, but it DOES NOT mean we are already just above
|
||||
* the topmost managed window. This is important because if
|
||||
* an override redirect window is up, and we map a new
|
||||
* managed window, the new window is probably above the old
|
||||
* popup by default, and we want to push it below that
|
||||
* popup. So keep looking for a sibling managed window
|
||||
* to be moved below.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
MetaWindow *other = meta_display_lookup_x_window (screen->display,
|
||||
other_window->x11.xwindow);
|
||||
|
||||
if (other != NULL && !other->override_redirect)
|
||||
return other_window;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* All wayland windows are currently considered "managed"
|
||||
* TODO: consider wayland pop-up windows like override
|
||||
* redirect windows here. */
|
||||
return other_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* When moving an X window we sometimes need an X based sibling.
|
||||
*
|
||||
* If the given sibling is X based this function returns it back
|
||||
* otherwise it searches downwards looking for the nearest X window.
|
||||
*
|
||||
* If no X based sibling could be found return NULL. */
|
||||
static MetaStackWindow *
|
||||
find_x11_sibling_downwards (MetaScreen *screen,
|
||||
MetaStackWindow *sibling)
|
||||
{
|
||||
MetaStackTracker *stack_tracker = screen->stack_tracker;
|
||||
MetaStackWindow *windows;
|
||||
int n_windows;
|
||||
int i;
|
||||
|
||||
if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
return sibling;
|
||||
|
||||
meta_stack_tracker_get_stack (stack_tracker,
|
||||
&windows, &n_windows);
|
||||
|
||||
/* NB: Children are in order from bottom to top and we
|
||||
* want to search downwards for the nearest X window.
|
||||
*/
|
||||
|
||||
for (i = n_windows - 1; i >= 0; i--)
|
||||
if (meta_stack_window_equal (&windows[i], sibling))
|
||||
break;
|
||||
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
return &windows[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* raise_window_relative_to_managed_windows:
|
||||
*
|
||||
@ -1053,84 +1166,74 @@ stack_ensure_sorted (MetaStack *stack)
|
||||
*/
|
||||
static void
|
||||
raise_window_relative_to_managed_windows (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
const MetaStackWindow *window)
|
||||
{
|
||||
gulong serial = 0;
|
||||
MetaStackWindow *sibling;
|
||||
|
||||
Window *children;
|
||||
int n_children;
|
||||
int i;
|
||||
|
||||
meta_stack_tracker_get_stack (screen->stack_tracker,
|
||||
&children, &n_children);
|
||||
|
||||
/* Children are in order from bottom to top. We want to
|
||||
* find the topmost managed child, then configure
|
||||
* our window to be above it.
|
||||
*/
|
||||
i = n_children - 1;
|
||||
while (i >= 0)
|
||||
sibling = find_top_most_managed_window (screen, window);
|
||||
if (!sibling)
|
||||
{
|
||||
if (children[i] == xwindow)
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
/* Do nothing. This means we're already the topmost managed
|
||||
* window, but it DOES NOT mean we are already just above
|
||||
* the topmost managed window. This is important because if
|
||||
* an override redirect window is up, and we map a new
|
||||
* managed window, the new window is probably above the old
|
||||
* popup by default, and we want to push it below that
|
||||
* popup. So keep looking for a sibling managed window
|
||||
* to be moved below.
|
||||
*/
|
||||
serial = XNextRequest (screen->display->xdisplay);
|
||||
meta_error_trap_push (screen->display);
|
||||
XLowerWindow (screen->display->xdisplay,
|
||||
window->x11.xwindow);
|
||||
meta_error_trap_pop (screen->display);
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaWindow *other = meta_display_lookup_x_window (screen->display,
|
||||
children[i]);
|
||||
if (other != NULL && !other->override_redirect)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
|
||||
/* children[i] is the topmost managed child */
|
||||
/* No sibling to use, just lower ourselves to the bottom
|
||||
* to be sure we're below any override redirect windows.
|
||||
*/
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
window,
|
||||
serial);
|
||||
return;
|
||||
}
|
||||
|
||||
/* window is the topmost managed child */
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Moving 0x%lx above topmost managed child window 0x%lx\n",
|
||||
xwindow, children[i]);
|
||||
window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0,
|
||||
sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0);
|
||||
|
||||
changes.sibling = children[i];
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling);
|
||||
serial = XNextRequest (screen->display->xdisplay);
|
||||
|
||||
if (x11_sibling)
|
||||
{
|
||||
changes.sibling = x11_sibling->x11.xwindow;
|
||||
changes.stack_mode = Above;
|
||||
|
||||
meta_error_trap_push (screen->display);
|
||||
meta_stack_tracker_record_raise_above (screen->stack_tracker,
|
||||
xwindow,
|
||||
children[i],
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
XConfigureWindow (screen->display->xdisplay,
|
||||
xwindow,
|
||||
window->x11.xwindow,
|
||||
CWSibling | CWStackMode,
|
||||
&changes);
|
||||
meta_error_trap_pop (screen->display);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
else
|
||||
{
|
||||
/* No sibling to use, just lower ourselves to the bottom
|
||||
* to be sure we're below any override redirect windows.
|
||||
*/
|
||||
meta_error_trap_push (screen->display);
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
xwindow,
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
XLowerWindow (screen->display->xdisplay,
|
||||
xwindow);
|
||||
window->x11.xwindow);
|
||||
meta_error_trap_pop (screen->display);
|
||||
}
|
||||
}
|
||||
|
||||
meta_stack_tracker_record_raise_above (screen->stack_tracker,
|
||||
window,
|
||||
sibling,
|
||||
serial);
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_sync_to_server:
|
||||
*
|
||||
@ -1145,13 +1248,16 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
|
||||
* job of computing the minimal set of stacking requests needed.
|
||||
*/
|
||||
static void
|
||||
stack_sync_to_server (MetaStack *stack)
|
||||
stack_sync_to_xserver (MetaStack *stack)
|
||||
{
|
||||
GArray *stacked;
|
||||
GArray *root_children_stacked;
|
||||
GArray *x11_stacked;
|
||||
GArray *x11_root_children_stacked;
|
||||
GArray *all_root_children_stacked; /* wayland OR x11 */
|
||||
GList *tmp;
|
||||
GArray *all_hidden;
|
||||
GArray *x11_hidden;
|
||||
GArray *x11_hidden_stack_windows;
|
||||
int n_override_redirect = 0;
|
||||
MetaStackWindow guard_stack_window;
|
||||
|
||||
/* Bail out if frozen */
|
||||
if (stack->freeze_count > 0)
|
||||
@ -1166,13 +1272,17 @@ stack_sync_to_server (MetaStack *stack)
|
||||
* _NET hints, and "root_children_stacked" is in top-to-bottom
|
||||
* order for XRestackWindows()
|
||||
*/
|
||||
stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
|
||||
x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
|
||||
x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
/* The screen guard window sits above all hidden windows and acts as
|
||||
* a barrier to input reaching these windows. */
|
||||
g_array_append_val (all_hidden, stack->screen->guard_window);
|
||||
g_array_append_val (x11_hidden, stack->screen->guard_window);
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
|
||||
meta_push_no_msg_prefix ();
|
||||
@ -1181,6 +1291,9 @@ stack_sync_to_server (MetaStack *stack)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
Window top_level_window;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
stack_window.any.type = w->client_type;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
||||
w->layer, w->stack_position, w->desc);
|
||||
@ -1189,60 +1302,93 @@ stack_sync_to_server (MetaStack *stack)
|
||||
if (w->override_redirect)
|
||||
n_override_redirect++;
|
||||
else
|
||||
g_array_prepend_val (stacked, w->xwindow);
|
||||
g_array_prepend_val (x11_stacked, w->xwindow);
|
||||
|
||||
if (w->frame)
|
||||
top_level_window = w->frame->xwindow;
|
||||
else
|
||||
top_level_window = w->xwindow;
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
stack_window.x11.xwindow = top_level_window;
|
||||
else
|
||||
stack_window.wayland.meta_window = w;
|
||||
|
||||
/* We don't restack hidden windows along with the rest, though they are
|
||||
* reflected in the _NET hints. Hidden windows all get pushed below
|
||||
* the screens fullscreen guard_window. */
|
||||
if (w->hidden)
|
||||
{
|
||||
g_array_append_val (all_hidden, top_level_window);
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = top_level_window;
|
||||
|
||||
g_array_append_val (x11_hidden_stack_windows, stack_window);
|
||||
g_array_append_val (x11_hidden, top_level_window);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
g_array_append_val (all_root_children_stacked, stack_window);
|
||||
|
||||
/* build XRestackWindows() array from top to bottom */
|
||||
g_array_append_val (root_children_stacked, top_level_window);
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
g_array_append_val (x11_root_children_stacked, top_level_window);
|
||||
else
|
||||
{
|
||||
MetaStackWindow *new;
|
||||
|
||||
/* So we can determine later if a cached stack window is
|
||||
* stale because the corresponding window has been freed we
|
||||
* associate a weak pointer with the new window. */
|
||||
new = &g_array_index (all_root_children_stacked, MetaStackWindow, all_root_children_stacked->len - 1);
|
||||
g_object_add_weak_pointer (G_OBJECT (new->wayland.meta_window),
|
||||
(gpointer *)&new->wayland.meta_window);
|
||||
}
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "\n");
|
||||
meta_pop_no_msg_prefix ();
|
||||
|
||||
/* All windows should be in some stacking order */
|
||||
if (stacked->len != stack->windows->len - n_override_redirect)
|
||||
/* All X windows should be in some stacking order */
|
||||
if (x11_stacked->len != stack->xwindows->len - n_override_redirect)
|
||||
meta_bug ("%u windows stacked, %u windows exist in stack\n",
|
||||
stacked->len, stack->windows->len);
|
||||
x11_stacked->len, stack->xwindows->len);
|
||||
|
||||
/* Sync to server */
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
||||
root_children_stacked->len);
|
||||
all_root_children_stacked->len);
|
||||
|
||||
meta_error_trap_push (stack->screen->display);
|
||||
|
||||
if (stack->last_root_children_stacked == NULL)
|
||||
if (stack->last_all_root_children_stacked == NULL)
|
||||
{
|
||||
/* Just impose our stack, we don't know the previous state.
|
||||
* This involves a ton of circulate requests and may flicker.
|
||||
*/
|
||||
meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
|
||||
|
||||
if (root_children_stacked->len > 0)
|
||||
if (all_root_children_stacked->len > 1)
|
||||
{
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *) root_children_stacked->data,
|
||||
root_children_stacked->len,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
gulong serial = 0;
|
||||
if (x11_root_children_stacked->len > 1)
|
||||
{
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *) root_children_stacked->data,
|
||||
root_children_stacked->len);
|
||||
(Window *) x11_root_children_stacked->data,
|
||||
x11_root_children_stacked->len);
|
||||
}
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(MetaStackWindow *) all_root_children_stacked->data,
|
||||
all_root_children_stacked->len,
|
||||
serial);
|
||||
}
|
||||
}
|
||||
else if (root_children_stacked->len > 0)
|
||||
else if (all_root_children_stacked->len > 0)
|
||||
{
|
||||
/* Try to do minimal window moves to get the stack in order */
|
||||
/* A point of note: these arrays include frames not client windows,
|
||||
@ -1250,28 +1396,34 @@ stack_sync_to_server (MetaStack *stack)
|
||||
* was saved, then we may have inefficiency, but I don't think things
|
||||
* break...
|
||||
*/
|
||||
const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
|
||||
const Window *new_stack = (Window *) root_children_stacked->data;
|
||||
const int old_len = stack->last_root_children_stacked->len;
|
||||
const int new_len = root_children_stacked->len;
|
||||
const Window *oldp = old_stack;
|
||||
const Window *newp = new_stack;
|
||||
const Window *old_end = old_stack + old_len;
|
||||
const Window *new_end = new_stack + new_len;
|
||||
Window last_window = None;
|
||||
|
||||
const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data;
|
||||
const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data;
|
||||
const int old_len = stack->last_all_root_children_stacked->len;
|
||||
const int new_len = all_root_children_stacked->len;
|
||||
const MetaStackWindow *oldp = old_stack;
|
||||
const MetaStackWindow *newp = new_stack;
|
||||
const MetaStackWindow *old_end = old_stack + old_len;
|
||||
const MetaStackWindow *new_end = new_stack + new_len;
|
||||
Window last_xwindow = None;
|
||||
const MetaStackWindow *last_window = NULL;
|
||||
|
||||
while (oldp != old_end &&
|
||||
newp != new_end)
|
||||
{
|
||||
if (*oldp == *newp)
|
||||
if (meta_stack_window_equal (oldp, newp))
|
||||
{
|
||||
/* Stacks are the same here, move on */
|
||||
++oldp;
|
||||
last_window = *newp;
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
last_xwindow = newp->x11.xwindow;
|
||||
last_window = newp;
|
||||
++newp;
|
||||
}
|
||||
else if (meta_display_lookup_x_window (stack->screen->display,
|
||||
*oldp) == NULL)
|
||||
else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
meta_display_lookup_x_window (stack->screen->display,
|
||||
oldp->x11.xwindow) == NULL) ||
|
||||
(oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
|
||||
oldp->wayland.meta_window == NULL))
|
||||
{
|
||||
/* *oldp is no longer known to us (probably destroyed),
|
||||
* so we can just skip it
|
||||
@ -1280,75 +1432,161 @@ stack_sync_to_server (MetaStack *stack)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move *newp below last_window */
|
||||
if (last_window == None)
|
||||
/* Move *newp below the last_window */
|
||||
if (!last_window)
|
||||
{
|
||||
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);
|
||||
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n",
|
||||
newp->x11.xwindow);
|
||||
|
||||
raise_window_relative_to_managed_windows (stack->screen,
|
||||
*newp);
|
||||
raise_window_relative_to_managed_windows (stack->screen, newp);
|
||||
}
|
||||
else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
last_xwindow == None)
|
||||
{
|
||||
/* In this case we have an X window that we need to
|
||||
* put below a wayland window and this is the
|
||||
* topmost X window. */
|
||||
|
||||
/* In X terms (because this is the topmost X window)
|
||||
* we want to
|
||||
* raise_window_relative_to_managed_windows() to
|
||||
* ensure the X window is below override-redirect
|
||||
* pop-up windows.
|
||||
*
|
||||
* In Wayland terms we just want to ensure
|
||||
* newp is lowered below last_window (which
|
||||
* notably doesn't require an X request because we
|
||||
* know last_window isn't an X window).
|
||||
*/
|
||||
|
||||
raise_window_relative_to_managed_windows (stack->screen, newp);
|
||||
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
newp, last_window,
|
||||
0); /* no x request serial */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This means that if last_window is dead, but not
|
||||
gulong serial = 0;
|
||||
|
||||
/* This means that if last_xwindow is dead, but not
|
||||
* *newp, then we fail to restack *newp; but on
|
||||
* unmanaging last_window, we'll fix it up.
|
||||
* unmanaging last_xwindow, we'll fix it up.
|
||||
*/
|
||||
|
||||
XWindowChanges changes;
|
||||
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
|
||||
newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0,
|
||||
last_xwindow);
|
||||
|
||||
changes.sibling = last_window;
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
|
||||
changes.sibling = last_xwindow;
|
||||
changes.stack_mode = Below;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
|
||||
*newp, last_window);
|
||||
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
*newp, last_window,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XConfigureWindow (stack->screen->display->xdisplay,
|
||||
*newp,
|
||||
newp->x11.xwindow,
|
||||
CWSibling | CWStackMode,
|
||||
&changes);
|
||||
}
|
||||
|
||||
last_window = *newp;
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
newp, last_window,
|
||||
serial);
|
||||
}
|
||||
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
last_xwindow = newp->x11.xwindow;
|
||||
last_window = newp;
|
||||
++newp;
|
||||
}
|
||||
}
|
||||
|
||||
if (newp != new_end)
|
||||
{
|
||||
const MetaStackWindow *x_ref;
|
||||
unsigned long serial = 0;
|
||||
|
||||
/* Restack remaining windows */
|
||||
meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
|
||||
(int) (new_end - newp));
|
||||
|
||||
/* rewind until we find the last stacked X window that we can use
|
||||
* as a reference point for re-stacking remaining X windows */
|
||||
if (newp != new_stack)
|
||||
for (x_ref = newp - 1;
|
||||
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
|
||||
x_ref--)
|
||||
;
|
||||
else
|
||||
x_ref = new_stack;
|
||||
|
||||
/* If we didn't find an X window looking backwards then walk forwards
|
||||
* through the remaining windows to find the first remaining X window
|
||||
* instead. */
|
||||
if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
for (x_ref = newp;
|
||||
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
|
||||
x_ref++)
|
||||
;
|
||||
}
|
||||
|
||||
/* If there are any X windows remaining unstacked then restack them */
|
||||
if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = x11_root_children_stacked->len - 1; i; i--)
|
||||
{
|
||||
Window *reference = &g_array_index (x11_root_children_stacked, Window, i);
|
||||
|
||||
if (*reference == x_ref->x11.xwindow)
|
||||
{
|
||||
int n = x11_root_children_stacked->len - i;
|
||||
|
||||
/* There's no point restacking if there's only one X window */
|
||||
if (n == 1)
|
||||
break;
|
||||
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
reference, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to include an already-stacked window
|
||||
* in the restack call, so we get in the proper position
|
||||
* with respect to it.
|
||||
*/
|
||||
if (newp != new_stack)
|
||||
--newp;
|
||||
newp = MIN (newp - 1, x_ref);
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *) newp, new_end - newp,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *) newp, new_end - newp);
|
||||
newp, new_end - newp,
|
||||
serial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Push hidden windows to the bottom of the stack under the guard window */
|
||||
/* Push hidden X windows to the bottom of the stack under the guard window */
|
||||
guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
guard_stack_window.x11.xwindow = stack->screen->guard_window;
|
||||
meta_stack_tracker_record_lower (stack->screen->stack_tracker,
|
||||
stack->screen->guard_window,
|
||||
&guard_stack_window,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *)all_hidden->data,
|
||||
all_hidden->len,
|
||||
(MetaStackWindow *)x11_hidden_stack_windows->data,
|
||||
x11_hidden_stack_windows->len,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *)all_hidden->data,
|
||||
all_hidden->len);
|
||||
g_array_free (all_hidden, TRUE);
|
||||
(Window *)x11_hidden->data,
|
||||
x11_hidden->len);
|
||||
g_array_free (x11_hidden, TRUE);
|
||||
g_array_free (x11_hidden_stack_windows, TRUE);
|
||||
|
||||
meta_error_trap_pop (stack->screen->display);
|
||||
/* on error, a window was destroyed; it should eventually
|
||||
@ -1363,21 +1601,23 @@ stack_sync_to_server (MetaStack *stack)
|
||||
stack->screen->display->atom__NET_CLIENT_LIST,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stack->windows->data,
|
||||
stack->windows->len);
|
||||
(unsigned char *)stack->xwindows->data,
|
||||
stack->xwindows->len);
|
||||
XChangeProperty (stack->screen->display->xdisplay,
|
||||
stack->screen->xroot,
|
||||
stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stacked->data,
|
||||
stacked->len);
|
||||
(unsigned char *)x11_stacked->data,
|
||||
x11_stacked->len);
|
||||
|
||||
g_array_free (stacked, TRUE);
|
||||
g_array_free (x11_stacked, TRUE);
|
||||
|
||||
if (stack->last_root_children_stacked)
|
||||
g_array_free (stack->last_root_children_stacked, TRUE);
|
||||
stack->last_root_children_stacked = root_children_stacked;
|
||||
if (stack->last_all_root_children_stacked)
|
||||
free_last_all_root_children_stacked_cache (stack);
|
||||
stack->last_all_root_children_stacked = all_root_children_stacked;
|
||||
|
||||
g_array_free (x11_root_children_stacked, TRUE);
|
||||
|
||||
/* That was scary... */
|
||||
}
|
||||
@ -1738,7 +1978,7 @@ meta_stack_set_positions (MetaStack *stack,
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Reset the stack positions of (nearly) all windows\n");
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@ -1801,7 +2041,7 @@ meta_window_set_stack_position (MetaWindow *window,
|
||||
int position)
|
||||
{
|
||||
meta_window_set_stack_position_no_sync (window, position);
|
||||
stack_sync_to_server (window->screen->stack);
|
||||
stack_sync_to_xserver (window->screen->stack);
|
||||
meta_stack_update_window_tile_matches (window->screen->stack,
|
||||
window->screen->active_workspace);
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ struct _MetaStack
|
||||
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
||||
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
||||
*/
|
||||
GArray *windows;
|
||||
GArray *xwindows;
|
||||
|
||||
/** The MetaWindows of the windows we manage, sorted in order. */
|
||||
GList *sorted;
|
||||
@ -99,7 +99,7 @@ struct _MetaStack
|
||||
* The last-known stack of all windows, bottom to top. We cache it here
|
||||
* so that subsequent times we'll be able to do incremental moves.
|
||||
*/
|
||||
GArray *last_root_children_stacked;
|
||||
GArray *last_all_root_children_stacked;
|
||||
|
||||
/**
|
||||
* Number of stack positions; same as the length of added, but
|
||||
|
@ -55,6 +55,7 @@ static gint verbose_topics = 0;
|
||||
static gboolean is_debugging = FALSE;
|
||||
static gboolean replace_current = FALSE;
|
||||
static int no_prefix = 0;
|
||||
static gboolean is_wayland_compositor = FALSE;
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static FILE* logfile = NULL;
|
||||
@ -194,6 +195,18 @@ meta_set_replace_current_wm (gboolean setting)
|
||||
replace_current = setting;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_is_wayland_compositor (void)
|
||||
{
|
||||
return is_wayland_compositor;
|
||||
}
|
||||
|
||||
void
|
||||
meta_set_is_wayland_compositor (gboolean value)
|
||||
{
|
||||
is_wayland_compositor = value;
|
||||
}
|
||||
|
||||
char *
|
||||
meta_g_utf8_strndup (const gchar *src,
|
||||
gsize n)
|
||||
|
@ -44,6 +44,15 @@
|
||||
#include <X11/Xutil.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
/* XXX: We should find a nicer approach to deal with the
|
||||
* circular dependency we have with the current headers
|
||||
* (meta-wayland-private.h which typedefs MetaWaylandSurface
|
||||
* also includes window-private.h) */
|
||||
#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
|
||||
typedef struct _MetaWaylandSurface MetaWaylandSurface;
|
||||
#endif
|
||||
|
||||
typedef struct _MetaWindowQueue MetaWindowQueue;
|
||||
|
||||
@ -69,6 +78,7 @@ typedef enum {
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
|
||||
} MetaBypassCompositorHintValue;
|
||||
|
||||
|
||||
struct _MetaWindow
|
||||
{
|
||||
GObject parent_instance;
|
||||
@ -77,6 +87,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;
|
||||
@ -325,9 +339,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 +360,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;
|
||||
@ -490,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);
|
||||
@ -665,7 +686,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);
|
||||
|
||||
@ -679,4 +699,16 @@ 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);
|
||||
|
||||
#endif
|
||||
|
@ -565,7 +565,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
|
||||
|
@ -62,6 +62,8 @@
|
||||
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
/* Windows that unmaximize to a size bigger than that fraction of the workarea
|
||||
* will be scaled down to that size (while maintaining aspect ratio).
|
||||
* Windows that cover an area greater then this size are automaximized on map.
|
||||
@ -713,10 +715,10 @@ meta_window_new (MetaDisplay *display,
|
||||
* Returns TRUE if window has been filtered out and should be ignored.
|
||||
*/
|
||||
static gboolean
|
||||
maybe_filter_window (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
XWindowAttributes *attrs)
|
||||
maybe_filter_xwindow (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
XWindowAttributes *attrs)
|
||||
{
|
||||
static char **filter_wm_classes = NULL;
|
||||
static gboolean initialized = FALSE;
|
||||
@ -812,80 +814,23 @@ meta_window_should_attach_to_parent (MetaWindow *window)
|
||||
}
|
||||
}
|
||||
|
||||
MetaWindow*
|
||||
meta_window_new_with_attrs (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
MetaCompEffect effect,
|
||||
XWindowAttributes *attrs)
|
||||
static MetaWindow*
|
||||
meta_window_new_shared (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaWindowClientType client_type,
|
||||
MetaWaylandSurface *surface,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
gulong existing_wm_state,
|
||||
MetaCompEffect effect,
|
||||
XWindowAttributes *attrs)
|
||||
{
|
||||
MetaWindow *window;
|
||||
GSList *tmp;
|
||||
MetaWorkspace *space;
|
||||
gulong existing_wm_state;
|
||||
gulong event_mask;
|
||||
MetaMoveResizeFlags flags;
|
||||
gboolean has_shape;
|
||||
MetaScreen *screen;
|
||||
|
||||
g_assert (attrs != NULL);
|
||||
|
||||
meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
|
||||
|
||||
if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
|
||||
{
|
||||
meta_verbose ("Not managing no_focus_window 0x%lx\n",
|
||||
xwindow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
screen = NULL;
|
||||
for (tmp = display->screens; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
MetaScreen *scr = tmp->data;
|
||||
|
||||
if (scr->xroot == attrs->root)
|
||||
{
|
||||
screen = tmp->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (screen);
|
||||
|
||||
/* A black list of override redirect windows that we don't need to manage: */
|
||||
if (attrs->override_redirect &&
|
||||
(xwindow == screen->no_focus_window ||
|
||||
xwindow == screen->flash_window ||
|
||||
xwindow == screen->wm_sn_selection_window ||
|
||||
attrs->class == InputOnly ||
|
||||
/* any windows created via meta_create_offscreen_window: */
|
||||
(attrs->x == -100 && attrs->y == -100
|
||||
&& attrs->width == 1 && attrs->height == 1) ||
|
||||
xwindow == screen->wm_cm_selection_window ||
|
||||
xwindow == screen->guard_window ||
|
||||
(display->compositor &&
|
||||
xwindow == XCompositeGetOverlayWindow (display->xdisplay,
|
||||
screen->xroot)
|
||||
)
|
||||
)
|
||||
) {
|
||||
meta_verbose ("Not managing our own windows\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (maybe_filter_window (display, xwindow, must_be_viewable, attrs))
|
||||
{
|
||||
meta_verbose ("Not managing filtered window\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Grab server */
|
||||
meta_display_grab (display);
|
||||
meta_error_trap_push (display); /* Push a trap over all of window
|
||||
* creation, to reduce XSync() calls
|
||||
*/
|
||||
|
||||
meta_verbose ("must_be_viewable = %d attrs->map_state = %d (%s)\n",
|
||||
must_be_viewable,
|
||||
attrs->map_state,
|
||||
@ -897,126 +842,14 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
"IsUnviewable" :
|
||||
"(unknown)");
|
||||
|
||||
existing_wm_state = WithdrawnState;
|
||||
if (must_be_viewable && attrs->map_state != IsViewable)
|
||||
{
|
||||
/* Only manage if WM_STATE is IconicState or NormalState */
|
||||
gulong state;
|
||||
|
||||
/* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
|
||||
if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
|
||||
display->atom_WM_STATE,
|
||||
display->atom_WM_STATE,
|
||||
&state) &&
|
||||
(state == IconicState || state == NormalState)))
|
||||
{
|
||||
meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
|
||||
meta_error_trap_pop (display);
|
||||
meta_display_ungrab (display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
existing_wm_state = state;
|
||||
meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
|
||||
wm_state_to_string (existing_wm_state));
|
||||
}
|
||||
|
||||
meta_error_trap_push_with_return (display);
|
||||
|
||||
/*
|
||||
* XAddToSaveSet can only be called on windows created by a different client.
|
||||
* with Mutter we want to be able to create manageable windows from within
|
||||
* the process (such as a dummy desktop window), so we do not want this
|
||||
* call failing to prevent the window from being managed -- wrap it in its
|
||||
* own error trap (we use the _with_return() version here to ensure that
|
||||
* XSync() is done on the pop, otherwise the error will not get caught).
|
||||
*/
|
||||
meta_error_trap_push_with_return (display);
|
||||
XAddToSaveSet (display->xdisplay, xwindow);
|
||||
meta_error_trap_pop_with_return (display);
|
||||
|
||||
event_mask = PropertyChangeMask | ColormapChangeMask;
|
||||
if (attrs->override_redirect)
|
||||
event_mask |= StructureNotifyMask;
|
||||
|
||||
/* If the window is from this client (a menu, say) we need to augment
|
||||
* the event mask, not replace it. For windows from other clients,
|
||||
* attrs->your_event_mask will be empty at this point.
|
||||
*/
|
||||
XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
|
||||
|
||||
{
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
|
||||
XISelectEvents (display->xdisplay, xwindow, &mask, 1);
|
||||
}
|
||||
|
||||
has_shape = FALSE;
|
||||
#ifdef HAVE_SHAPE
|
||||
if (META_DISPLAY_HAS_SHAPE (display))
|
||||
{
|
||||
int x_bounding, y_bounding, x_clip, y_clip;
|
||||
unsigned w_bounding, h_bounding, w_clip, h_clip;
|
||||
int bounding_shaped, clip_shaped;
|
||||
|
||||
XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
|
||||
|
||||
XShapeQueryExtents (display->xdisplay, xwindow,
|
||||
&bounding_shaped, &x_bounding, &y_bounding,
|
||||
&w_bounding, &h_bounding,
|
||||
&clip_shaped, &x_clip, &y_clip,
|
||||
&w_clip, &h_clip);
|
||||
|
||||
has_shape = bounding_shaped != FALSE;
|
||||
|
||||
meta_topic (META_DEBUG_SHAPES,
|
||||
"Window has_shape = %d extents %d,%d %u x %u\n",
|
||||
has_shape, x_bounding, y_bounding,
|
||||
w_bounding, h_bounding);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get rid of any borders */
|
||||
if (attrs->border_width != 0)
|
||||
XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
|
||||
|
||||
/* Get rid of weird gravities */
|
||||
if (attrs->win_gravity != NorthWestGravity)
|
||||
{
|
||||
XSetWindowAttributes set_attrs;
|
||||
|
||||
set_attrs.win_gravity = NorthWestGravity;
|
||||
|
||||
XChangeWindowAttributes (display->xdisplay,
|
||||
xwindow,
|
||||
CWWinGravity,
|
||||
&set_attrs);
|
||||
}
|
||||
|
||||
if (meta_error_trap_pop_with_return (display) != Success)
|
||||
{
|
||||
meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
|
||||
xwindow);
|
||||
meta_error_trap_pop (display);
|
||||
meta_display_ungrab (display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
window = g_object_new (META_TYPE_WINDOW, NULL);
|
||||
|
||||
window->constructing = TRUE;
|
||||
|
||||
window->dialog_pid = -1;
|
||||
|
||||
window->client_type = client_type;
|
||||
window->surface = surface;
|
||||
window->xwindow = xwindow;
|
||||
|
||||
/* this is in window->screen->display, but that's too annoying to
|
||||
@ -1041,8 +874,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
/* avoid tons of stack updates */
|
||||
meta_stack_freeze (window->screen->stack);
|
||||
|
||||
window->has_shape = has_shape;
|
||||
|
||||
window->rect.x = attrs->x;
|
||||
window->rect.y = attrs->y;
|
||||
window->rect.width = attrs->width;
|
||||
@ -1142,7 +973,11 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
window->mwm_has_move_func = TRUE;
|
||||
window->mwm_has_resize_func = TRUE;
|
||||
|
||||
window->decorated = TRUE;
|
||||
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
window->decorated = TRUE;
|
||||
else
|
||||
window->decorated = FALSE;
|
||||
|
||||
window->has_close_func = TRUE;
|
||||
window->has_minimize_func = TRUE;
|
||||
window->has_maximize_func = TRUE;
|
||||
@ -1201,23 +1036,28 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
|
||||
window->tile_match = NULL;
|
||||
|
||||
if (window->override_redirect)
|
||||
{
|
||||
window->decorated = FALSE;
|
||||
window->always_sticky = TRUE;
|
||||
window->has_close_func = FALSE;
|
||||
window->has_shade_func = FALSE;
|
||||
window->has_move_func = FALSE;
|
||||
window->has_resize_func = FALSE;
|
||||
}
|
||||
|
||||
meta_display_register_x_window (display, &window->xwindow, window);
|
||||
|
||||
/* Assign this #MetaWindow a sequence number which can be used
|
||||
* for sorting.
|
||||
*/
|
||||
window->stable_sequence = ++display->window_sequence_counter;
|
||||
|
||||
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
if (window->override_redirect)
|
||||
{
|
||||
window->decorated = FALSE;
|
||||
window->always_sticky = TRUE;
|
||||
window->has_close_func = FALSE;
|
||||
window->has_shade_func = FALSE;
|
||||
window->has_move_func = FALSE;
|
||||
window->has_resize_func = FALSE;
|
||||
}
|
||||
|
||||
meta_display_register_x_window (display, &window->xwindow, window);
|
||||
meta_window_update_shape_region_x11 (window);
|
||||
meta_window_update_input_region_x11 (window);
|
||||
}
|
||||
|
||||
/* assign the window to its group, or create a new group if needed
|
||||
*/
|
||||
window->group = NULL;
|
||||
@ -1226,7 +1066,8 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
|
||||
meta_window_load_initial_properties (window);
|
||||
|
||||
if (!window->override_redirect)
|
||||
if (!window->override_redirect &&
|
||||
client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
update_sm_hints (window); /* must come after transient_for */
|
||||
|
||||
@ -1300,6 +1141,16 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
if (window->decorated)
|
||||
meta_window_ensure_frame (window);
|
||||
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
MetaStackWindow stack_window;
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
|
||||
stack_window.wayland.meta_window = window;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
&stack_window,
|
||||
0);
|
||||
}
|
||||
|
||||
meta_window_grab_keys (window);
|
||||
if (window->type != META_WINDOW_DOCK && !window->override_redirect)
|
||||
{
|
||||
@ -1500,11 +1351,14 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
!window->initially_iconic)
|
||||
unminimize_window_and_all_transient_parents (window);
|
||||
|
||||
meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
|
||||
meta_display_ungrab (display);
|
||||
|
||||
window->constructing = FALSE;
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static void
|
||||
display_notify_window (MetaDisplay *display, MetaWindow *window)
|
||||
{
|
||||
meta_display_notify_window_created (display, window);
|
||||
|
||||
if (window->wm_state_demands_attention)
|
||||
@ -1512,6 +1366,254 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
||||
|
||||
if (window->wm_hints_urgent)
|
||||
g_signal_emit_by_name (window->display, "window-marked-urgent", window);
|
||||
}
|
||||
|
||||
MetaWindow *
|
||||
meta_window_new_for_wayland (MetaDisplay *display,
|
||||
int width,
|
||||
int height,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
XWindowAttributes attrs;
|
||||
MetaScreen *scr = display->screens->data;
|
||||
MetaWindow *window;
|
||||
|
||||
attrs.x = 0;
|
||||
attrs.y = 0;
|
||||
attrs.width = width;
|
||||
attrs.height = height;
|
||||
attrs.border_width = 0;
|
||||
attrs.depth = 24;
|
||||
attrs.visual = NULL;
|
||||
attrs.root = scr->xroot;
|
||||
attrs.class = InputOutput;
|
||||
attrs.bit_gravity = NorthWestGravity;
|
||||
attrs.win_gravity = NorthWestGravity;
|
||||
attrs.backing_store = 0;
|
||||
attrs.backing_planes = ~0;
|
||||
attrs.backing_pixel = 0;
|
||||
attrs.save_under = 0;
|
||||
attrs.colormap = 0;
|
||||
attrs.map_installed = 1;
|
||||
attrs.map_state = IsUnmapped;
|
||||
attrs.all_event_masks = ~0;
|
||||
attrs.your_event_mask = 0;
|
||||
attrs.do_not_propagate_mask = 0;
|
||||
attrs.override_redirect = 0;
|
||||
attrs.screen = scr->xscreen;
|
||||
|
||||
/* XXX: Note: In the Wayland case we currently still grab the
|
||||
* xserver and trap X errors while creating a MetaWindow because we
|
||||
* will still be making various redundant X requests (passing a
|
||||
* window xid of None) until we thoroughly audit all the code to
|
||||
* make sure it knows about non X based clients...
|
||||
*/
|
||||
|
||||
/* Grab server */
|
||||
meta_display_grab (display);
|
||||
meta_error_trap_push (display); /* Push a trap over all of window
|
||||
* creation, to reduce XSync() calls
|
||||
*/
|
||||
|
||||
window = meta_window_new_shared (display,
|
||||
scr,
|
||||
META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
surface,
|
||||
None,
|
||||
TRUE,
|
||||
WithdrawnState,
|
||||
META_COMP_EFFECT_NONE,
|
||||
&attrs);
|
||||
|
||||
meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
|
||||
meta_display_ungrab (display);
|
||||
|
||||
/* XXX: Maybe this could be called in meta_window_new_shared() but
|
||||
* before splitting the X11 specific code out it came after the
|
||||
* meta_display_ungrab() and we wanted to minimize the risk of
|
||||
* breaking something.
|
||||
*/
|
||||
display_notify_window (window->display, window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
MetaWindow*
|
||||
meta_window_new_with_attrs (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
MetaCompEffect effect,
|
||||
XWindowAttributes *attrs)
|
||||
{
|
||||
MetaScreen *screen = NULL;
|
||||
GSList *tmp;
|
||||
gulong existing_wm_state;
|
||||
MetaWindow *window;
|
||||
gulong event_mask;
|
||||
|
||||
meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
|
||||
|
||||
if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
|
||||
{
|
||||
meta_verbose ("Not managing no_focus_window 0x%lx\n",
|
||||
xwindow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (tmp = display->screens; tmp != NULL; tmp = tmp->next)
|
||||
{
|
||||
MetaScreen *scr = tmp->data;
|
||||
|
||||
if (scr->xroot == attrs->root)
|
||||
{
|
||||
screen = tmp->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (screen);
|
||||
|
||||
/* A black list of override redirect windows that we don't need to manage: */
|
||||
if (attrs->override_redirect &&
|
||||
(xwindow == screen->no_focus_window ||
|
||||
xwindow == screen->flash_window ||
|
||||
xwindow == screen->wm_sn_selection_window ||
|
||||
attrs->class == InputOnly ||
|
||||
/* any windows created via meta_create_offscreen_window: */
|
||||
(attrs->x == -100 && attrs->y == -100
|
||||
&& attrs->width == 1 && attrs->height == 1) ||
|
||||
xwindow == screen->wm_cm_selection_window ||
|
||||
xwindow == screen->guard_window ||
|
||||
(display->compositor &&
|
||||
xwindow == XCompositeGetOverlayWindow (display->xdisplay,
|
||||
screen->xroot)
|
||||
)
|
||||
)
|
||||
) {
|
||||
meta_verbose ("Not managing our own windows\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (maybe_filter_xwindow (display, xwindow, must_be_viewable, attrs))
|
||||
{
|
||||
meta_verbose ("Not managing filtered window\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Grab server */
|
||||
meta_display_grab (display);
|
||||
meta_error_trap_push (display); /* Push a trap over all of window
|
||||
* creation, to reduce XSync() calls
|
||||
*/
|
||||
|
||||
existing_wm_state = WithdrawnState;
|
||||
if (must_be_viewable && attrs->map_state != IsViewable)
|
||||
{
|
||||
/* Only manage if WM_STATE is IconicState or NormalState */
|
||||
gulong state;
|
||||
|
||||
/* WM_STATE isn't a cardinal, it's type WM_STATE, but is an int */
|
||||
if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
|
||||
display->atom_WM_STATE,
|
||||
display->atom_WM_STATE,
|
||||
&state) &&
|
||||
(state == IconicState || state == NormalState)))
|
||||
{
|
||||
meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
|
||||
meta_error_trap_pop (display);
|
||||
meta_display_ungrab (display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
existing_wm_state = state;
|
||||
meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
|
||||
wm_state_to_string (existing_wm_state));
|
||||
}
|
||||
|
||||
meta_error_trap_push_with_return (display);
|
||||
|
||||
/*
|
||||
* XAddToSaveSet can only be called on windows created by a different
|
||||
* client. with Mutter we want to be able to create manageable windows
|
||||
* from within the process (such as a dummy desktop window), so we do not
|
||||
* want this call failing to prevent the window from being managed -- wrap
|
||||
* it in its own error trap (we use the _with_return() version here to
|
||||
* ensure that XSync() is done on the pop, otherwise the error will not
|
||||
* get caught).
|
||||
*/
|
||||
meta_error_trap_push_with_return (display);
|
||||
XAddToSaveSet (display->xdisplay, xwindow);
|
||||
meta_error_trap_pop_with_return (display);
|
||||
|
||||
event_mask = PropertyChangeMask | ColormapChangeMask;
|
||||
if (attrs->override_redirect)
|
||||
event_mask |= StructureNotifyMask;
|
||||
|
||||
/* If the window is from this client (a menu, say) we need to augment
|
||||
* the event mask, not replace it. For windows from other clients,
|
||||
* attrs->your_event_mask will be empty at this point.
|
||||
*/
|
||||
XSelectInput (display->xdisplay, xwindow, attrs->your_event_mask | event_mask);
|
||||
|
||||
{
|
||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
||||
|
||||
meta_core_add_old_event_mask (display->xdisplay, xwindow, &mask);
|
||||
|
||||
XISetMask (mask.mask, XI_Enter);
|
||||
XISetMask (mask.mask, XI_Leave);
|
||||
XISetMask (mask.mask, XI_FocusIn);
|
||||
XISetMask (mask.mask, XI_FocusOut);
|
||||
|
||||
XISelectEvents (display->xdisplay, xwindow, &mask, 1);
|
||||
}
|
||||
|
||||
/* Get rid of any borders */
|
||||
if (attrs->border_width != 0)
|
||||
XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
|
||||
|
||||
/* Get rid of weird gravities */
|
||||
if (attrs->win_gravity != NorthWestGravity)
|
||||
{
|
||||
XSetWindowAttributes set_attrs;
|
||||
|
||||
set_attrs.win_gravity = NorthWestGravity;
|
||||
|
||||
XChangeWindowAttributes (display->xdisplay,
|
||||
xwindow,
|
||||
CWWinGravity,
|
||||
&set_attrs);
|
||||
}
|
||||
|
||||
if (meta_error_trap_pop_with_return (display) != Success)
|
||||
{
|
||||
meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
|
||||
xwindow);
|
||||
meta_error_trap_pop (display);
|
||||
meta_display_ungrab (display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
window = meta_window_new_shared (display,
|
||||
screen,
|
||||
META_WINDOW_CLIENT_TYPE_X11,
|
||||
NULL,
|
||||
xwindow,
|
||||
must_be_viewable,
|
||||
existing_wm_state,
|
||||
effect,
|
||||
attrs);
|
||||
|
||||
meta_error_trap_pop (display); /* pop the XSync()-reducing trap */
|
||||
meta_display_ungrab (display);
|
||||
|
||||
/* XXX: Maybe this could be called in meta_window_new_shared() but
|
||||
* before splitting the X11 specific code out it came after the
|
||||
* meta_display_ungrab() and we wanted to minimize the risk of
|
||||
* breaking something.
|
||||
*/
|
||||
display_notify_window (display, window);
|
||||
|
||||
return window;
|
||||
}
|
||||
@ -1682,6 +1784,16 @@ meta_window_unmanage (MetaWindow *window,
|
||||
|
||||
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
|
||||
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
MetaStackWindow stack_window;
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_WAYLAND;
|
||||
stack_window.wayland.meta_window = window;
|
||||
meta_stack_tracker_record_remove (window->screen->stack_tracker,
|
||||
&stack_window,
|
||||
0);
|
||||
}
|
||||
|
||||
if (window->display->compositor)
|
||||
{
|
||||
if (window->visible_to_compositor)
|
||||
@ -1888,48 +2000,53 @@ meta_window_unmanage (MetaWindow *window,
|
||||
meta_display_ungrab_window_buttons (window->display, window->xwindow);
|
||||
meta_display_ungrab_focus_window_button (window->display, window);
|
||||
|
||||
meta_display_unregister_x_window (window->display, window->xwindow);
|
||||
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
|
||||
/* Put back anything we messed up */
|
||||
if (window->border_width != 0)
|
||||
XSetWindowBorderWidth (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
window->border_width);
|
||||
|
||||
/* No save set */
|
||||
XRemoveFromSaveSet (window->display->xdisplay,
|
||||
window->xwindow);
|
||||
|
||||
/* Even though the window is now unmanaged, we can't unselect events. This
|
||||
* window might be a window from this process, like a GdkMenu, in
|
||||
* which case it will have pointer events and so forth selected
|
||||
* for it by GDK. There's no way to disentangle those events from the events
|
||||
* we've selected. Even for a window from a different X client,
|
||||
* GDK could also have selected events for it for IPC purposes, so we
|
||||
* can't unselect in that case either.
|
||||
*
|
||||
* Similarly, we can't unselected for events on window->user_time_window.
|
||||
* It might be our own GDK focus window, or it might be a window that a
|
||||
* different client is using for multiple different things:
|
||||
* _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
|
||||
*/
|
||||
|
||||
if (window->user_time_window != None)
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
meta_display_unregister_x_window (window->display,
|
||||
window->user_time_window);
|
||||
window->user_time_window = None;
|
||||
}
|
||||
meta_display_unregister_x_window (window->display, window->xwindow);
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
|
||||
/* Put back anything we messed up */
|
||||
if (window->border_width != 0)
|
||||
XSetWindowBorderWidth (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
window->border_width);
|
||||
|
||||
/* No save set */
|
||||
XRemoveFromSaveSet (window->display->xdisplay,
|
||||
window->xwindow);
|
||||
|
||||
/* Even though the window is now unmanaged, we can't unselect events. This
|
||||
* window might be a window from this process, like a GdkMenu, in
|
||||
* which case it will have pointer events and so forth selected
|
||||
* for it by GDK. There's no way to disentangle those events from the events
|
||||
* we've selected. Even for a window from a different X client,
|
||||
* GDK could also have selected events for it for IPC purposes, so we
|
||||
* can't unselect in that case either.
|
||||
*
|
||||
* Similarly, we can't unselected for events on window->user_time_window.
|
||||
* It might be our own GDK focus window, or it might be a window that a
|
||||
* different client is using for multiple different things:
|
||||
* _NET_WM_USER_TIME_WINDOW and IPC, perhaps.
|
||||
*/
|
||||
|
||||
if (window->user_time_window != None)
|
||||
{
|
||||
meta_display_unregister_x_window (window->display,
|
||||
window->user_time_window);
|
||||
window->user_time_window = None;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SHAPE
|
||||
if (META_DISPLAY_HAS_SHAPE (window->display))
|
||||
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
|
||||
if (META_DISPLAY_HAS_SHAPE (window->display))
|
||||
XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
|
||||
#endif
|
||||
|
||||
meta_error_trap_pop (window->display);
|
||||
meta_error_trap_pop (window->display);
|
||||
}
|
||||
|
||||
if (window->surface)
|
||||
meta_wayland_surface_free (window->surface);
|
||||
|
||||
meta_prefs_remove_listener (prefs_changed_callback, window);
|
||||
|
||||
@ -5831,7 +5948,7 @@ meta_window_get_outer_rect (const MetaWindow *window,
|
||||
|
||||
if (window->has_custom_frame_extents)
|
||||
{
|
||||
GtkBorder *extents = &window->custom_frame_extents;
|
||||
const GtkBorder *extents = &window->custom_frame_extents;
|
||||
rect->x += extents->left;
|
||||
rect->y += extents->top;
|
||||
rect->width -= extents->left + extents->right;
|
||||
@ -7637,14 +7754,25 @@ meta_window_update_net_wm_type (MetaWindow *window)
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_update_opaque_region (MetaWindow *window)
|
||||
meta_window_set_opaque_region (MetaWindow *window,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
g_clear_pointer (&window->opaque_region, cairo_region_destroy);
|
||||
|
||||
if (region != NULL)
|
||||
window->opaque_region = cairo_region_reference (region);
|
||||
|
||||
if (window->display->compositor)
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_update_opaque_region_x11 (MetaWindow *window)
|
||||
{
|
||||
cairo_region_t *opaque_region = NULL;
|
||||
gulong *region = NULL;
|
||||
int nitems;
|
||||
|
||||
g_clear_pointer (&window->opaque_region, cairo_region_destroy);
|
||||
|
||||
if (meta_prop_get_cardinal_list (window->display,
|
||||
window->xwindow,
|
||||
window->display->atom__NET_WM_OPAQUE_REGION,
|
||||
@ -7687,13 +7815,193 @@ meta_window_update_opaque_region (MetaWindow *window)
|
||||
}
|
||||
|
||||
out:
|
||||
window->opaque_region = opaque_region;
|
||||
meta_XFree (region);
|
||||
|
||||
meta_window_set_opaque_region (window, opaque_region);
|
||||
cairo_region_destroy (opaque_region);
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
region_create_from_x_rectangles (const XRectangle *rects,
|
||||
int n_rects)
|
||||
{
|
||||
int i;
|
||||
cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
|
||||
|
||||
for (i = 0; i < n_rects; i ++)
|
||||
{
|
||||
cairo_rects[i].x = rects[i].x;
|
||||
cairo_rects[i].y = rects[i].y;
|
||||
cairo_rects[i].width = rects[i].width;
|
||||
cairo_rects[i].height = rects[i].height;
|
||||
}
|
||||
|
||||
return cairo_region_create_rectangles (cairo_rects, n_rects);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_set_input_region (MetaWindow *window,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
g_clear_pointer (&window->input_region, cairo_region_destroy);
|
||||
|
||||
if (region != NULL)
|
||||
window->input_region = cairo_region_reference (region);
|
||||
|
||||
if (window->display->compositor)
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_update_input_region_x11 (MetaWindow *window)
|
||||
{
|
||||
cairo_region_t *region = NULL;
|
||||
|
||||
#ifdef HAVE_SHAPE
|
||||
if (META_DISPLAY_HAS_SHAPE (window->display))
|
||||
{
|
||||
/* Translate the set of XShape rectangles that we
|
||||
* get from the X server to a cairo_region. */
|
||||
XRectangle *rects = NULL;
|
||||
int n_rects, ordering;
|
||||
|
||||
int x_bounding, y_bounding, x_clip, y_clip;
|
||||
unsigned w_bounding, h_bounding, w_clip, h_clip;
|
||||
int bounding_shaped, clip_shaped;
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
XShapeQueryExtents (window->display->xdisplay, window->xwindow,
|
||||
&bounding_shaped, &x_bounding, &y_bounding,
|
||||
&w_bounding, &h_bounding,
|
||||
&clip_shaped, &x_clip, &y_clip,
|
||||
&w_clip, &h_clip);
|
||||
|
||||
rects = XShapeGetRectangles (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
ShapeInput,
|
||||
&n_rects,
|
||||
&ordering);
|
||||
meta_error_trap_pop (window->display);
|
||||
|
||||
/* XXX: The x shape extension doesn't provide a way to only test if an
|
||||
* input shape has been specified, so we have to query and throw away the
|
||||
* rectangles. */
|
||||
if (rects)
|
||||
{
|
||||
if (n_rects > 1 ||
|
||||
(n_rects == 1 &&
|
||||
(rects[0].x != x_bounding ||
|
||||
rects[1].y != y_bounding ||
|
||||
rects[2].width != w_bounding ||
|
||||
rects[3].height != h_bounding)))
|
||||
region = region_create_from_x_rectangles (rects, n_rects);
|
||||
|
||||
XFree (rects);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SHAPE */
|
||||
|
||||
if (region != NULL)
|
||||
{
|
||||
cairo_rectangle_int_t client_area;
|
||||
|
||||
client_area.x = 0;
|
||||
client_area.y = 0;
|
||||
client_area.width = window->rect.width;
|
||||
client_area.height = window->rect.height;
|
||||
|
||||
/* The shape we get back from the client may have coordinates
|
||||
* outside of the frame. The X SHAPE Extension requires that
|
||||
* the overall shape the client provides never exceeds the
|
||||
* "bounding rectangle" of the window -- the shape that the
|
||||
* window would have gotten if it was unshaped. In our case,
|
||||
* this is simply the client area.
|
||||
*/
|
||||
cairo_region_intersect_rectangle (region, &client_area);
|
||||
}
|
||||
|
||||
meta_window_set_input_region (window, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_set_shape_region (MetaWindow *window,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
g_clear_pointer (&window->shape_region, cairo_region_destroy);
|
||||
|
||||
if (region != NULL)
|
||||
window->shape_region = cairo_region_reference (region);
|
||||
|
||||
if (window->display->compositor)
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_update_shape_region_x11 (MetaWindow *window)
|
||||
{
|
||||
cairo_region_t *region = NULL;
|
||||
|
||||
#ifdef HAVE_SHAPE
|
||||
if (META_DISPLAY_HAS_SHAPE (window->display))
|
||||
{
|
||||
/* Translate the set of XShape rectangles that we
|
||||
* get from the X server to a cairo_region. */
|
||||
XRectangle *rects = NULL;
|
||||
int n_rects, ordering;
|
||||
|
||||
int x_bounding, y_bounding, x_clip, y_clip;
|
||||
unsigned w_bounding, h_bounding, w_clip, h_clip;
|
||||
int bounding_shaped, clip_shaped;
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
XShapeQueryExtents (window->display->xdisplay, window->xwindow,
|
||||
&bounding_shaped, &x_bounding, &y_bounding,
|
||||
&w_bounding, &h_bounding,
|
||||
&clip_shaped, &x_clip, &y_clip,
|
||||
&w_clip, &h_clip);
|
||||
|
||||
if (bounding_shaped)
|
||||
{
|
||||
rects = XShapeGetRectangles (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
ShapeBounding,
|
||||
&n_rects,
|
||||
&ordering);
|
||||
}
|
||||
meta_error_trap_pop (window->display);
|
||||
|
||||
if (rects)
|
||||
{
|
||||
region = region_create_from_x_rectangles (rects, n_rects);
|
||||
XFree (rects);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SHAPE */
|
||||
|
||||
if (region != NULL)
|
||||
{
|
||||
cairo_rectangle_int_t client_area;
|
||||
|
||||
client_area.x = 0;
|
||||
client_area.y = 0;
|
||||
client_area.width = window->rect.width;
|
||||
client_area.height = window->rect.height;
|
||||
|
||||
/* The shape we get back from the client may have coordinates
|
||||
* outside of the frame. The X SHAPE Extension requires that
|
||||
* the overall shape the client provides never exceeds the
|
||||
* "bounding rectangle" of the window -- the shape that the
|
||||
* window would have gotten if it was unshaped. In our case,
|
||||
* this is simply the client area.
|
||||
*/
|
||||
cairo_region_intersect_rectangle (region, &client_area);
|
||||
}
|
||||
|
||||
meta_window_set_shape_region (window, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
static void
|
||||
redraw_icon (MetaWindow *window)
|
||||
{
|
||||
@ -8395,10 +8703,13 @@ recalc_window_features (MetaWindow *window)
|
||||
|
||||
case META_WINDOW_DIALOG:
|
||||
case META_WINDOW_MODAL_DIALOG:
|
||||
/* only skip taskbar if we have a real transient parent */
|
||||
/* only skip taskbar if we have a real transient parent
|
||||
(and ignore the application hints) */
|
||||
if (window->xtransient_for != None &&
|
||||
window->xtransient_for != window->screen->xroot)
|
||||
window->skip_taskbar = TRUE;
|
||||
else
|
||||
window->skip_taskbar = FALSE;
|
||||
break;
|
||||
|
||||
case META_WINDOW_NORMAL:
|
||||
|
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}
|
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
|
@ -396,8 +396,6 @@ typedef enum {
|
||||
|
||||
gboolean
|
||||
meta_plugin_begin_modal (MetaPlugin *plugin,
|
||||
Window grab_window,
|
||||
Cursor cursor,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp);
|
||||
|
||||
|
@ -64,8 +64,6 @@ 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);
|
||||
|
||||
@ -75,18 +73,20 @@ void meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
|
||||
Pixmap pixmap);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -56,6 +56,8 @@ struct _MetaUI
|
||||
void
|
||||
meta_ui_init (void)
|
||||
{
|
||||
gdk_set_allowed_backends ("x11");
|
||||
|
||||
if (!gtk_init_check (NULL, NULL))
|
||||
meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
|
||||
}
|
||||
|
548
src/wayland/meta-wayland-data-device.c
Normal file
548
src/wayland/meta-wayland-data-device.c
Normal file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright © 2011 Kristian Høgsberg
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The file is based on src/data-device.c from Weston */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "meta-wayland-data-device.h"
|
||||
#include "meta-wayland-seat.h"
|
||||
#include "meta-wayland-pointer.h"
|
||||
|
||||
static void
|
||||
data_offer_accept (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
guint32 serial,
|
||||
const char *mime_type)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
/* FIXME: Check that client is currently focused by the input
|
||||
* device that is currently dragging this data source. Should
|
||||
* this be a wl_data_device request? */
|
||||
|
||||
if (offer->source)
|
||||
offer->source->accept (offer->source, serial, mime_type);
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_receive (struct wl_client *client, struct wl_resource *resource,
|
||||
const char *mime_type, int32_t fd)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
if (offer->source)
|
||||
offer->source->send (offer->source, mime_type, fd);
|
||||
else
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_destroy (struct wl_client *client, struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_interface data_offer_interface = {
|
||||
data_offer_accept,
|
||||
data_offer_receive,
|
||||
data_offer_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_data_offer (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
if (offer->source)
|
||||
wl_list_remove (&offer->source_destroy_listener.link);
|
||||
free (offer);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_offer_data_source (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandDataOffer *offer;
|
||||
|
||||
offer = wl_container_of (listener, offer, source_destroy_listener);
|
||||
|
||||
offer->source = NULL;
|
||||
}
|
||||
|
||||
static struct wl_resource *
|
||||
meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
|
||||
struct wl_resource *target)
|
||||
{
|
||||
MetaWaylandDataOffer *offer;
|
||||
char **p;
|
||||
|
||||
offer = malloc (sizeof *offer);
|
||||
if (offer == NULL)
|
||||
return NULL;
|
||||
|
||||
offer->source = source;
|
||||
offer->source_destroy_listener.notify = destroy_offer_data_source;
|
||||
|
||||
offer->resource = wl_client_add_object (wl_resource_get_client (target),
|
||||
&wl_data_offer_interface,
|
||||
&data_offer_interface,
|
||||
0,
|
||||
offer);
|
||||
wl_resource_set_destructor (offer->resource, destroy_data_offer);
|
||||
wl_resource_add_destroy_listener (source->resource,
|
||||
&offer->source_destroy_listener);
|
||||
|
||||
wl_data_device_send_data_offer (target, offer->resource);
|
||||
|
||||
wl_array_for_each (p, &source->mime_types)
|
||||
wl_data_offer_send_offer (offer->resource, *p);
|
||||
|
||||
return offer->resource;
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_offer (struct wl_client *client,
|
||||
struct wl_resource *resource, const char *type)
|
||||
{
|
||||
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
|
||||
char **p;
|
||||
|
||||
p = wl_array_add (&source->mime_types, sizeof *p);
|
||||
if (p)
|
||||
*p = strdup (type);
|
||||
if (!p || !*p)
|
||||
wl_resource_post_no_memory (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_destroy (struct wl_client *client, struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static struct wl_data_source_interface data_source_interface = {
|
||||
data_source_offer,
|
||||
data_source_destroy
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_drag_focus (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (listener, seat, drag_focus_listener);
|
||||
|
||||
seat->drag_focus_resource = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
|
||||
struct wl_resource *resource, *offer = NULL;
|
||||
struct wl_display *display;
|
||||
guint32 serial;
|
||||
|
||||
if (seat->drag_focus_resource)
|
||||
{
|
||||
wl_data_device_send_leave (seat->drag_focus_resource);
|
||||
wl_list_remove (&seat->drag_focus_listener.link);
|
||||
seat->drag_focus_resource = NULL;
|
||||
seat->drag_focus = NULL;
|
||||
}
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
if (!seat->drag_data_source &&
|
||||
wl_resource_get_client (surface->resource) != seat->drag_client)
|
||||
return;
|
||||
|
||||
resource =
|
||||
wl_resource_find_for_client (&seat->drag_resource_list,
|
||||
wl_resource_get_client (surface->resource));
|
||||
if (!resource)
|
||||
return;
|
||||
|
||||
display = wl_client_get_display (wl_resource_get_client (resource));
|
||||
serial = wl_display_next_serial (display);
|
||||
|
||||
if (seat->drag_data_source)
|
||||
offer = meta_wayland_data_source_send_offer (seat->drag_data_source,
|
||||
resource);
|
||||
|
||||
wl_data_device_send_enter (resource, serial, surface->resource,
|
||||
x, y, offer);
|
||||
|
||||
seat->drag_focus = surface;
|
||||
seat->drag_focus_listener.notify = destroy_drag_focus;
|
||||
wl_resource_add_destroy_listener (resource, &seat->drag_focus_listener);
|
||||
seat->drag_focus_resource = resource;
|
||||
grab->focus = surface;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_motion (MetaWaylandPointerGrab *grab,
|
||||
guint32 time, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
|
||||
|
||||
if (seat->drag_focus_resource)
|
||||
wl_data_device_send_motion (seat->drag_focus_resource, time, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
data_device_end_drag_grab (MetaWaylandSeat *seat)
|
||||
{
|
||||
if (seat->drag_surface)
|
||||
{
|
||||
seat->drag_surface = NULL;
|
||||
wl_signal_emit (&seat->drag_icon_signal, NULL);
|
||||
wl_list_remove (&seat->drag_icon_listener.link);
|
||||
}
|
||||
|
||||
drag_grab_focus (&seat->drag_grab, NULL,
|
||||
wl_fixed_from_int (0), wl_fixed_from_int (0));
|
||||
|
||||
meta_wayland_pointer_end_grab (&seat->pointer);
|
||||
|
||||
seat->drag_data_source = NULL;
|
||||
seat->drag_client = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_button (MetaWaylandPointerGrab *grab,
|
||||
guint32 time, guint32 button, guint32 state_w)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
|
||||
enum wl_pointer_button_state state = state_w;
|
||||
|
||||
if (seat->drag_focus_resource &&
|
||||
seat->pointer.grab_button == button &&
|
||||
state == WL_POINTER_BUTTON_STATE_RELEASED)
|
||||
wl_data_device_send_drop (seat->drag_focus_resource);
|
||||
|
||||
if (seat->pointer.button_count == 0 &&
|
||||
state == WL_POINTER_BUTTON_STATE_RELEASED)
|
||||
{
|
||||
if (seat->drag_data_source)
|
||||
wl_list_remove (&seat->drag_data_source_listener.link);
|
||||
data_device_end_drag_grab (seat);
|
||||
}
|
||||
}
|
||||
|
||||
static const MetaWaylandPointerGrabInterface drag_grab_interface = {
|
||||
drag_grab_focus,
|
||||
drag_grab_motion,
|
||||
drag_grab_button,
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_data_device_source (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandSeat *seat =
|
||||
wl_container_of (listener, seat, drag_data_source_listener);
|
||||
|
||||
data_device_end_drag_grab (seat);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_data_device_icon (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandSeat *seat =
|
||||
wl_container_of (listener, seat, drag_icon_listener);
|
||||
|
||||
seat->drag_surface = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
data_device_start_drag (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *source_resource,
|
||||
struct wl_resource *origin_resource,
|
||||
struct wl_resource *icon_resource, guint32 serial)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
|
||||
/* FIXME: Check that client has implicit grab on the origin
|
||||
* surface that matches the given time. */
|
||||
|
||||
/* FIXME: Check that the data source type array isn't empty. */
|
||||
|
||||
seat->drag_grab.interface = &drag_grab_interface;
|
||||
|
||||
seat->drag_client = client;
|
||||
seat->drag_data_source = NULL;
|
||||
|
||||
if (source_resource)
|
||||
{
|
||||
seat->drag_data_source = wl_resource_get_user_data (source_resource);
|
||||
seat->drag_data_source_listener.notify = destroy_data_device_source;
|
||||
wl_resource_add_destroy_listener (source_resource,
|
||||
&seat->drag_data_source_listener);
|
||||
}
|
||||
|
||||
if (icon_resource)
|
||||
{
|
||||
seat->drag_surface = wl_resource_get_user_data (icon_resource);
|
||||
seat->drag_icon_listener.notify = destroy_data_device_icon;
|
||||
wl_resource_add_destroy_listener (icon_resource,
|
||||
&seat->drag_icon_listener);
|
||||
wl_signal_emit (&seat->drag_icon_signal, icon_resource);
|
||||
}
|
||||
|
||||
meta_wayland_pointer_set_focus (&seat->pointer, NULL,
|
||||
wl_fixed_from_int (0),
|
||||
wl_fixed_from_int (0));
|
||||
meta_wayland_pointer_start_grab (&seat->pointer, &seat->drag_grab);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_selection_data_source (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandSeat *seat =
|
||||
wl_container_of (listener, seat, selection_data_source_listener);
|
||||
struct wl_resource *data_device;
|
||||
struct wl_resource *focus = NULL;
|
||||
|
||||
seat->selection_data_source = NULL;
|
||||
|
||||
focus = seat->keyboard.focus_resource;
|
||||
|
||||
if (focus)
|
||||
{
|
||||
data_device =
|
||||
wl_resource_find_for_client (&seat->drag_resource_list,
|
||||
wl_resource_get_client (focus));
|
||||
if (data_device)
|
||||
wl_data_device_send_selection (data_device, NULL);
|
||||
}
|
||||
|
||||
wl_signal_emit (&seat->selection_signal, seat);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
|
||||
MetaWaylandDataSource *source,
|
||||
guint32 serial)
|
||||
{
|
||||
struct wl_resource *data_device, *offer;
|
||||
struct wl_resource *focus = NULL;
|
||||
|
||||
if (seat->selection_data_source &&
|
||||
seat->selection_serial - serial < UINT32_MAX / 2)
|
||||
return;
|
||||
|
||||
if (seat->selection_data_source)
|
||||
{
|
||||
seat->selection_data_source->cancel (seat->selection_data_source);
|
||||
wl_list_remove (&seat->selection_data_source_listener.link);
|
||||
seat->selection_data_source = NULL;
|
||||
}
|
||||
|
||||
seat->selection_data_source = source;
|
||||
seat->selection_serial = serial;
|
||||
|
||||
focus = seat->keyboard.focus_resource;
|
||||
|
||||
if (focus)
|
||||
{
|
||||
data_device =
|
||||
wl_resource_find_for_client (&seat->drag_resource_list,
|
||||
wl_resource_get_client (focus));
|
||||
if (data_device && source)
|
||||
{
|
||||
offer =
|
||||
meta_wayland_data_source_send_offer (seat->selection_data_source,
|
||||
data_device);
|
||||
wl_data_device_send_selection (data_device, offer);
|
||||
}
|
||||
else if (data_device)
|
||||
{
|
||||
wl_data_device_send_selection (data_device, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
wl_signal_emit (&seat->selection_signal, seat);
|
||||
|
||||
if (source)
|
||||
{
|
||||
seat->selection_data_source_listener.notify =
|
||||
destroy_selection_data_source;
|
||||
wl_resource_add_destroy_listener (source->resource,
|
||||
&seat->selection_data_source_listener);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
data_device_set_selection (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *source_resource,
|
||||
guint32 serial)
|
||||
{
|
||||
if (!source_resource)
|
||||
return;
|
||||
|
||||
/* FIXME: Store serial and check against incoming serial here. */
|
||||
meta_wayland_seat_set_selection (wl_resource_get_user_data (resource),
|
||||
wl_resource_get_user_data (source_resource),
|
||||
serial);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_interface data_device_interface = {
|
||||
data_device_start_drag,
|
||||
data_device_set_selection,
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_data_source (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataSource *source = wl_container_of (resource, source, resource);
|
||||
char **p;
|
||||
|
||||
wl_array_for_each (p, &source->mime_types) free (*p);
|
||||
|
||||
wl_array_release (&source->mime_types);
|
||||
}
|
||||
|
||||
static void
|
||||
client_source_accept (MetaWaylandDataSource *source,
|
||||
guint32 time, const char *mime_type)
|
||||
{
|
||||
wl_data_source_send_target (source->resource, mime_type);
|
||||
}
|
||||
|
||||
static void
|
||||
client_source_send (MetaWaylandDataSource *source,
|
||||
const char *mime_type, int32_t fd)
|
||||
{
|
||||
wl_data_source_send_send (source->resource, mime_type, fd);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
client_source_cancel (MetaWaylandDataSource *source)
|
||||
{
|
||||
wl_data_source_send_cancelled (source->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
create_data_source (struct wl_client *client,
|
||||
struct wl_resource *resource, guint32 id)
|
||||
{
|
||||
MetaWaylandDataSource *source;
|
||||
|
||||
source = malloc (sizeof *source);
|
||||
if (source == NULL)
|
||||
{
|
||||
wl_resource_post_no_memory (resource);
|
||||
return;
|
||||
}
|
||||
|
||||
source->resource = wl_client_add_object (client,
|
||||
&wl_data_source_interface,
|
||||
&data_source_interface,
|
||||
id,
|
||||
source);
|
||||
wl_resource_set_destructor (source->resource, destroy_data_source);
|
||||
|
||||
source->accept = client_source_accept;
|
||||
source->send = client_source_send;
|
||||
source->cancel = client_source_cancel;
|
||||
|
||||
wl_array_init (&source->mime_types);
|
||||
}
|
||||
|
||||
static void
|
||||
unbind_data_device (struct wl_resource *resource)
|
||||
{
|
||||
wl_list_remove (wl_resource_get_link (resource));
|
||||
}
|
||||
|
||||
static void
|
||||
get_data_device (struct wl_client *client,
|
||||
struct wl_resource *manager_resource,
|
||||
guint32 id, struct wl_resource *seat_resource)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = wl_client_add_object (client, &wl_data_device_interface,
|
||||
&data_device_interface, id, seat);
|
||||
|
||||
wl_list_insert (&seat->drag_resource_list, wl_resource_get_link (resource));
|
||||
wl_resource_set_destructor (resource, unbind_data_device);
|
||||
}
|
||||
|
||||
static const struct wl_data_device_manager_interface manager_interface = {
|
||||
create_data_source,
|
||||
get_data_device
|
||||
};
|
||||
|
||||
static void
|
||||
bind_manager (struct wl_client *client,
|
||||
void *data, guint32 version, guint32 id)
|
||||
{
|
||||
wl_client_add_object (client, &wl_data_device_manager_interface,
|
||||
&manager_interface, id, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat)
|
||||
{
|
||||
struct wl_resource *data_device, *focus, *offer;
|
||||
MetaWaylandDataSource *source;
|
||||
|
||||
focus = seat->keyboard.focus_resource;
|
||||
if (!focus)
|
||||
return;
|
||||
|
||||
data_device = wl_resource_find_for_client (&seat->drag_resource_list,
|
||||
wl_resource_get_client (focus));
|
||||
if (!data_device)
|
||||
return;
|
||||
|
||||
source = seat->selection_data_source;
|
||||
if (source)
|
||||
{
|
||||
offer = meta_wayland_data_source_send_offer (source, data_device);
|
||||
wl_data_device_send_selection (data_device, offer);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
meta_wayland_data_device_manager_init (struct wl_display *display)
|
||||
{
|
||||
if (wl_display_add_global (display,
|
||||
&wl_data_device_manager_interface,
|
||||
NULL, bind_manager) == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
42
src/wayland/meta-wayland-data-device.h
Normal file
42
src/wayland/meta-wayland-data-device.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright © 2008 Kristian Høgsberg
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __META_WAYLAND_DATA_DEVICE_H__
|
||||
#define __META_WAYLAND_DATA_DEVICE_H__
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "meta-wayland-seat.h"
|
||||
|
||||
void
|
||||
meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat);
|
||||
|
||||
int
|
||||
meta_wayland_data_device_manager_init (struct wl_display *display);
|
||||
|
||||
void
|
||||
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
|
||||
MetaWaylandDataSource *source,
|
||||
uint32_t serial);
|
||||
|
||||
|
||||
#endif /* __META_WAYLAND_DATA_DEVICE_H__ */
|
512
src/wayland/meta-wayland-keyboard.c
Normal file
512
src/wayland/meta-wayland-keyboard.c
Normal file
@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright © 2010-2011 Intel Corporation
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The file is based on src/input.c from Weston */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "meta-wayland-keyboard.h"
|
||||
|
||||
static MetaWaylandSeat *
|
||||
meta_wayland_keyboard_get_seat (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (keyboard, seat, keyboard);
|
||||
|
||||
return seat;
|
||||
}
|
||||
|
||||
static int
|
||||
create_anonymous_file (off_t size,
|
||||
GError **error)
|
||||
{
|
||||
static const char template[] = "mutter-shared-XXXXXX";
|
||||
char *path;
|
||||
int fd, flags;
|
||||
|
||||
fd = g_file_open_tmp (template, &path, error);
|
||||
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
unlink (path);
|
||||
g_free (path);
|
||||
|
||||
flags = fcntl (fd, F_GETFD);
|
||||
if (flags == -1)
|
||||
goto err;
|
||||
|
||||
if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
||||
goto err;
|
||||
|
||||
if (ftruncate (fd, size) < 0)
|
||||
goto err;
|
||||
|
||||
return fd;
|
||||
|
||||
err:
|
||||
g_set_error_literal (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
strerror (errno));
|
||||
close (fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
|
||||
{
|
||||
GError *error = NULL;
|
||||
char *keymap_str;
|
||||
|
||||
xkb_info->shift_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
|
||||
xkb_info->caps_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
|
||||
xkb_info->ctrl_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
|
||||
xkb_info->alt_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
|
||||
xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
|
||||
xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
|
||||
xkb_info->super_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
|
||||
xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
|
||||
|
||||
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
|
||||
if (keymap_str == NULL)
|
||||
{
|
||||
g_warning ("failed to get string version of keymap\n");
|
||||
return FALSE;
|
||||
}
|
||||
xkb_info->keymap_size = strlen (keymap_str) + 1;
|
||||
|
||||
xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
|
||||
if (xkb_info->keymap_fd < 0)
|
||||
{
|
||||
g_warning ("creating a keymap file for %lu bytes failed: %s\n",
|
||||
(unsigned long) xkb_info->keymap_size,
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
goto err_keymap_str;
|
||||
}
|
||||
|
||||
xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, xkb_info->keymap_fd, 0);
|
||||
if (xkb_info->keymap_area == MAP_FAILED)
|
||||
{
|
||||
g_warning ("failed to mmap() %lu bytes\n",
|
||||
(unsigned long) xkb_info->keymap_size);
|
||||
goto err_dev_zero;
|
||||
}
|
||||
strcpy (xkb_info->keymap_area, keymap_str);
|
||||
free (keymap_str);
|
||||
|
||||
return TRUE;
|
||||
|
||||
err_dev_zero:
|
||||
close (xkb_info->keymap_fd);
|
||||
xkb_info->keymap_fd = -1;
|
||||
err_keymap_str:
|
||||
free (keymap_str);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context,
|
||||
struct xkb_rule_names *xkb_names,
|
||||
MetaWaylandXkbInfo *xkb_info)
|
||||
{
|
||||
xkb_info->keymap = xkb_map_new_from_names (xkb_context,
|
||||
xkb_names,
|
||||
0 /* flags */);
|
||||
if (xkb_info->keymap == NULL)
|
||||
{
|
||||
g_warning ("failed to compile global XKB keymap\n"
|
||||
" tried rules %s, model %s, layout %s, variant %s, "
|
||||
"options %s\n",
|
||||
xkb_names->rules,
|
||||
xkb_names->model,
|
||||
xkb_names->layout,
|
||||
xkb_names->variant,
|
||||
xkb_names->options);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!meta_wayland_xkb_info_new_keymap (xkb_info))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
lose_keyboard_focus (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandKeyboard *keyboard =
|
||||
wl_container_of (listener, keyboard, focus_listener);
|
||||
|
||||
keyboard->focus_resource = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
default_grab_key (MetaWaylandKeyboardGrab *grab,
|
||||
uint32_t time, uint32_t key, uint32_t state)
|
||||
{
|
||||
MetaWaylandKeyboard *keyboard = grab->keyboard;
|
||||
struct wl_resource *resource;
|
||||
uint32_t serial;
|
||||
|
||||
resource = keyboard->focus_resource;
|
||||
if (resource)
|
||||
{
|
||||
struct wl_client *client = wl_resource_get_client (resource);
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
serial = wl_display_next_serial (display);
|
||||
wl_keyboard_send_key (resource, serial, time, key, state);
|
||||
}
|
||||
}
|
||||
|
||||
static struct wl_resource *
|
||||
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
|
||||
{
|
||||
struct wl_client *client;
|
||||
|
||||
if (!surface)
|
||||
return NULL;
|
||||
|
||||
if (!surface->resource)
|
||||
return NULL;
|
||||
|
||||
client = wl_resource_get_client (surface->resource);
|
||||
|
||||
return wl_resource_find_for_client (list, client);
|
||||
}
|
||||
|
||||
static void
|
||||
default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched,
|
||||
uint32_t mods_locked, uint32_t group)
|
||||
{
|
||||
MetaWaylandKeyboard *keyboard = grab->keyboard;
|
||||
MetaWaylandSeat *seat = meta_wayland_keyboard_get_seat (keyboard);
|
||||
MetaWaylandPointer *pointer = &seat->pointer;
|
||||
struct wl_resource *resource, *pr;
|
||||
|
||||
resource = keyboard->focus_resource;
|
||||
if (!resource)
|
||||
return;
|
||||
|
||||
wl_keyboard_send_modifiers (resource, serial, mods_depressed,
|
||||
mods_latched, mods_locked, group);
|
||||
|
||||
if (pointer && pointer->focus && pointer->focus != keyboard->focus)
|
||||
{
|
||||
pr = find_resource_for_surface (&keyboard->resource_list,
|
||||
pointer->focus);
|
||||
if (pr)
|
||||
{
|
||||
wl_keyboard_send_modifiers (pr,
|
||||
serial,
|
||||
keyboard->modifiers.mods_depressed,
|
||||
keyboard->modifiers.mods_latched,
|
||||
keyboard->modifiers.mods_locked,
|
||||
keyboard->modifiers.group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const MetaWaylandKeyboardGrabInterface
|
||||
default_keyboard_grab_interface = {
|
||||
default_grab_key,
|
||||
default_grab_modifiers,
|
||||
};
|
||||
|
||||
gboolean
|
||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
||||
struct wl_display *display)
|
||||
{
|
||||
memset (keyboard, 0, sizeof *keyboard);
|
||||
|
||||
wl_list_init (&keyboard->resource_list);
|
||||
wl_array_init (&keyboard->keys);
|
||||
keyboard->focus_listener.notify = lose_keyboard_focus;
|
||||
keyboard->default_grab.interface = &default_keyboard_grab_interface;
|
||||
keyboard->default_grab.keyboard = keyboard;
|
||||
keyboard->grab = &keyboard->default_grab;
|
||||
wl_signal_init (&keyboard->focus_signal);
|
||||
|
||||
keyboard->display = display;
|
||||
|
||||
keyboard->xkb_context = xkb_context_new (0 /* flags */);
|
||||
|
||||
meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
|
||||
&keyboard->xkb_names,
|
||||
&keyboard->xkb_info);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
|
||||
{
|
||||
if (xkb_info->keymap)
|
||||
xkb_map_unref (xkb_info->keymap);
|
||||
|
||||
if (xkb_info->keymap_area)
|
||||
munmap (xkb_info->keymap_area, xkb_info->keymap_size);
|
||||
if (xkb_info->keymap_fd >= 0)
|
||||
close (xkb_info->keymap_fd);
|
||||
}
|
||||
|
||||
static void
|
||||
set_modifiers (MetaWaylandKeyboard *keyboard,
|
||||
guint32 serial,
|
||||
ClutterModifierType modifier_state)
|
||||
{
|
||||
MetaWaylandKeyboardGrab *grab = keyboard->grab;
|
||||
uint32_t depressed_mods = 0;
|
||||
uint32_t locked_mods = 0;
|
||||
|
||||
if (keyboard->last_modifier_state == modifier_state)
|
||||
return;
|
||||
|
||||
if ((modifier_state & CLUTTER_SHIFT_MASK) &&
|
||||
keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_LOCK_MASK) &&
|
||||
keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
|
||||
locked_mods |= (1 << keyboard->xkb_info.caps_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_CONTROL_MASK) &&
|
||||
keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_MOD1_MASK) &&
|
||||
keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_MOD2_MASK) &&
|
||||
keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_MOD3_MASK) &&
|
||||
keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_SUPER_MASK) &&
|
||||
keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.super_mod);
|
||||
|
||||
if ((modifier_state & CLUTTER_MOD5_MASK) &&
|
||||
keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
|
||||
depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
|
||||
|
||||
keyboard->last_modifier_state = modifier_state;
|
||||
|
||||
grab->interface->modifiers (grab,
|
||||
serial,
|
||||
depressed_mods,
|
||||
0, /* latched_modes */
|
||||
locked_mods,
|
||||
0 /* group */);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterKeyEvent *event)
|
||||
{
|
||||
gboolean state = event->type == CLUTTER_KEY_PRESS;
|
||||
guint evdev_code;
|
||||
uint32_t serial;
|
||||
|
||||
/* We can't do anything with the event if we can't get an evdev
|
||||
keycode for it */
|
||||
if (event->device == NULL ||
|
||||
!clutter_input_device_keycode_to_evdev (event->device,
|
||||
event->hardware_keycode,
|
||||
&evdev_code))
|
||||
return;
|
||||
|
||||
/* We want to ignore events that are sent because of auto-repeat. In
|
||||
the Clutter event stream these appear as a single key press
|
||||
event. We can detect that because the key will already have been
|
||||
pressed */
|
||||
if (state)
|
||||
{
|
||||
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
||||
keyboard->keys.size);
|
||||
uint32_t *k;
|
||||
|
||||
/* Ignore the event if the key is already down */
|
||||
for (k = keyboard->keys.data; k < end; k++)
|
||||
if (*k == evdev_code)
|
||||
return;
|
||||
|
||||
/* Otherwise add the key to the list of pressed keys */
|
||||
k = wl_array_add (&keyboard->keys, sizeof (*k));
|
||||
*k = evdev_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
||||
keyboard->keys.size);
|
||||
uint32_t *k;
|
||||
|
||||
/* Remove the key from the array */
|
||||
for (k = keyboard->keys.data; k < end; k++)
|
||||
if (*k == evdev_code)
|
||||
{
|
||||
*k = *(end - 1);
|
||||
keyboard->keys.size -= sizeof (*k);
|
||||
|
||||
goto found;
|
||||
}
|
||||
|
||||
g_warning ("unexpected key release event for key 0x%x", evdev_code);
|
||||
|
||||
found:
|
||||
(void) 0;
|
||||
}
|
||||
|
||||
serial = wl_display_next_serial (keyboard->display);
|
||||
|
||||
set_modifiers (keyboard, serial, event->modifier_state);
|
||||
|
||||
keyboard->grab->interface->key (keyboard->grab,
|
||||
event->time,
|
||||
evdev_code,
|
||||
state);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
uint32_t serial;
|
||||
|
||||
if (keyboard->focus_resource && keyboard->focus != surface)
|
||||
{
|
||||
struct wl_display *display;
|
||||
struct wl_client *client;
|
||||
|
||||
resource = keyboard->focus_resource;
|
||||
client = wl_resource_get_client (resource);
|
||||
display = wl_client_get_display (client);
|
||||
serial = wl_display_next_serial (display);
|
||||
wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
|
||||
wl_list_remove (&keyboard->focus_listener.link);
|
||||
}
|
||||
|
||||
resource = find_resource_for_surface (&keyboard->resource_list, surface);
|
||||
if (resource &&
|
||||
(keyboard->focus != surface || keyboard->focus_resource != resource))
|
||||
{
|
||||
struct wl_client *client = wl_resource_get_client (resource);
|
||||
struct wl_display *display;
|
||||
|
||||
display = wl_client_get_display (client);
|
||||
serial = wl_display_next_serial (display);
|
||||
wl_keyboard_send_modifiers (resource, serial,
|
||||
keyboard->modifiers.mods_depressed,
|
||||
keyboard->modifiers.mods_latched,
|
||||
keyboard->modifiers.mods_locked,
|
||||
keyboard->modifiers.group);
|
||||
wl_keyboard_send_enter (resource, serial, surface->resource,
|
||||
&keyboard->keys);
|
||||
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
|
||||
keyboard->focus_serial = serial;
|
||||
}
|
||||
|
||||
keyboard->focus_resource = resource;
|
||||
keyboard->focus = surface;
|
||||
wl_signal_emit (&keyboard->focus_signal, keyboard);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard,
|
||||
MetaWaylandKeyboardGrab *grab)
|
||||
{
|
||||
keyboard->grab = grab;
|
||||
grab->keyboard = keyboard;
|
||||
|
||||
/* XXX focus? */
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
keyboard->grab = &keyboard->default_grab;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
g_free ((char *) keyboard->xkb_names.rules);
|
||||
g_free ((char *) keyboard->xkb_names.model);
|
||||
g_free ((char *) keyboard->xkb_names.layout);
|
||||
g_free ((char *) keyboard->xkb_names.variant);
|
||||
g_free ((char *) keyboard->xkb_names.options);
|
||||
|
||||
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
|
||||
xkb_context_unref (keyboard->xkb_context);
|
||||
|
||||
/* XXX: What about keyboard->resource_list? */
|
||||
if (keyboard->focus_resource)
|
||||
wl_list_remove (&keyboard->focus_listener.link);
|
||||
wl_array_release (&keyboard->keys);
|
||||
}
|
75
src/wayland/meta-wayland-keyboard.h
Normal file
75
src/wayland/meta-wayland-keyboard.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2012 Collabora, Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __META_WAYLAND_KEYBOARD_H__
|
||||
#define __META_WAYLAND_KEYBOARD_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "meta-wayland-seat.h"
|
||||
|
||||
gboolean
|
||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
||||
struct wl_display *display);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterKeyEvent *event);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
||||
MetaWaylandSurface *surface);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
|
||||
MetaWaylandKeyboardGrab *grab);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);
|
||||
|
||||
#endif /* __META_WAYLAND_KEYBOARD_H__ */
|
264
src/wayland/meta-wayland-pointer.c
Normal file
264
src/wayland/meta-wayland-pointer.c
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright © 2008 Kristian Høgsberg
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The file is based on src/input.c from Weston */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-wayland-pointer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static MetaWaylandSeat *
|
||||
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
|
||||
|
||||
return seat;
|
||||
}
|
||||
|
||||
static void
|
||||
lose_pointer_focus (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandPointer *pointer =
|
||||
wl_container_of (listener, pointer, focus_listener);
|
||||
|
||||
pointer->focus_resource = NULL;
|
||||
pointer->focus = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
default_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y)
|
||||
{
|
||||
MetaWaylandPointer *pointer = grab->pointer;
|
||||
|
||||
if (pointer->button_count > 0)
|
||||
return;
|
||||
|
||||
meta_wayland_pointer_set_focus (pointer, surface, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
default_grab_motion (MetaWaylandPointerGrab *grab,
|
||||
uint32_t time, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = grab->pointer->focus_resource;
|
||||
if (resource)
|
||||
wl_pointer_send_motion (resource, time, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
default_grab_button (MetaWaylandPointerGrab *grab,
|
||||
uint32_t time, uint32_t button, uint32_t state_w)
|
||||
{
|
||||
MetaWaylandPointer *pointer = grab->pointer;
|
||||
struct wl_resource *resource;
|
||||
uint32_t serial;
|
||||
enum wl_pointer_button_state state = state_w;
|
||||
|
||||
resource = pointer->focus_resource;
|
||||
if (resource)
|
||||
{
|
||||
struct wl_client *client = wl_resource_get_client (resource);
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
serial = wl_display_next_serial (display);
|
||||
wl_pointer_send_button (resource, serial, time, button, state_w);
|
||||
}
|
||||
|
||||
if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
|
||||
meta_wayland_pointer_set_focus (pointer, pointer->current,
|
||||
pointer->current_x, pointer->current_y);
|
||||
}
|
||||
|
||||
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
|
||||
default_grab_focus,
|
||||
default_grab_motion,
|
||||
default_grab_button
|
||||
};
|
||||
|
||||
void
|
||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer)
|
||||
{
|
||||
memset (pointer, 0, sizeof *pointer);
|
||||
wl_list_init (&pointer->resource_list);
|
||||
pointer->focus_listener.notify = lose_pointer_focus;
|
||||
pointer->default_grab.interface = &default_pointer_grab_interface;
|
||||
pointer->default_grab.pointer = pointer;
|
||||
pointer->grab = &pointer->default_grab;
|
||||
wl_signal_init (&pointer->focus_signal);
|
||||
|
||||
/* FIXME: Pick better co-ords. */
|
||||
pointer->x = wl_fixed_from_int (100);
|
||||
pointer->y = wl_fixed_from_int (100);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
|
||||
{
|
||||
/* XXX: What about pointer->resource_list? */
|
||||
if (pointer->focus_resource)
|
||||
wl_list_remove (&pointer->focus_listener.link);
|
||||
|
||||
pointer->focus = NULL;
|
||||
pointer->focus_resource = NULL;
|
||||
}
|
||||
|
||||
static struct wl_resource *
|
||||
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
|
||||
{
|
||||
struct wl_client *client;
|
||||
|
||||
if (!surface)
|
||||
return NULL;
|
||||
|
||||
g_assert (surface->resource);
|
||||
client = wl_resource_get_client (surface->resource);
|
||||
|
||||
return wl_resource_find_for_client (list, client);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
||||
MetaWaylandSurface *surface,
|
||||
wl_fixed_t sx, wl_fixed_t sy)
|
||||
{
|
||||
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
|
||||
MetaWaylandKeyboard *kbd = &seat->keyboard;
|
||||
struct wl_resource *resource, *kr;
|
||||
uint32_t serial;
|
||||
|
||||
resource = pointer->focus_resource;
|
||||
if (resource && pointer->focus != surface)
|
||||
{
|
||||
struct wl_client *client = wl_resource_get_client (resource);
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
serial = wl_display_next_serial (display);
|
||||
wl_pointer_send_leave (resource, serial, pointer->focus->resource);
|
||||
wl_list_remove (&pointer->focus_listener.link);
|
||||
}
|
||||
|
||||
resource = find_resource_for_surface (&pointer->resource_list, surface);
|
||||
if (resource &&
|
||||
(pointer->focus != surface || pointer->focus_resource != resource))
|
||||
{
|
||||
struct wl_client *client = wl_resource_get_client (resource);
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
serial = wl_display_next_serial (display);
|
||||
if (kbd)
|
||||
{
|
||||
kr = find_resource_for_surface (&kbd->resource_list, surface);
|
||||
if (kr)
|
||||
{
|
||||
wl_keyboard_send_modifiers (kr,
|
||||
serial,
|
||||
kbd->modifiers.mods_depressed,
|
||||
kbd->modifiers.mods_latched,
|
||||
kbd->modifiers.mods_locked,
|
||||
kbd->modifiers.group);
|
||||
}
|
||||
}
|
||||
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
|
||||
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
|
||||
pointer->focus_serial = serial;
|
||||
}
|
||||
|
||||
pointer->focus_resource = resource;
|
||||
pointer->focus = surface;
|
||||
pointer->default_grab.focus = surface;
|
||||
wl_signal_emit (&pointer->focus_signal, pointer);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
|
||||
MetaWaylandPointerGrab *grab)
|
||||
{
|
||||
const MetaWaylandPointerGrabInterface *interface;
|
||||
|
||||
pointer->grab = grab;
|
||||
interface = pointer->grab->interface;
|
||||
grab->pointer = pointer;
|
||||
|
||||
if (pointer->current)
|
||||
interface->focus (pointer->grab, pointer->current,
|
||||
pointer->current_x, pointer->current_y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
|
||||
{
|
||||
const MetaWaylandPointerGrabInterface *interface;
|
||||
|
||||
pointer->grab = &pointer->default_grab;
|
||||
interface = pointer->grab->interface;
|
||||
interface->focus (pointer->grab, pointer->current,
|
||||
pointer->current_x, pointer->current_y);
|
||||
}
|
||||
|
||||
static void
|
||||
current_surface_destroy (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandPointer *pointer =
|
||||
wl_container_of (listener, pointer, current_listener);
|
||||
|
||||
pointer->current = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
if (pointer->current)
|
||||
wl_list_remove (&pointer->current_listener.link);
|
||||
|
||||
pointer->current = surface;
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
wl_resource_add_destroy_listener (surface->resource,
|
||||
&pointer->current_listener);
|
||||
pointer->current_listener.notify = current_surface_destroy;
|
||||
}
|
49
src/wayland/meta-wayland-pointer.h
Normal file
49
src/wayland/meta-wayland-pointer.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __META_WAYLAND_POINTER_H__
|
||||
#define __META_WAYLAND_POINTER_H__
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "meta-wayland-seat.h"
|
||||
|
||||
void
|
||||
meta_wayland_pointer_init (MetaWaylandPointer *pointer);
|
||||
|
||||
void
|
||||
meta_wayland_pointer_release (MetaWaylandPointer *pointer);
|
||||
|
||||
void
|
||||
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
||||
MetaWaylandSurface *surface,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy);
|
||||
void
|
||||
meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
|
||||
MetaWaylandPointerGrab *grab);
|
||||
|
||||
void
|
||||
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
|
||||
|
||||
void
|
||||
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
|
||||
MetaWaylandSurface *surface);
|
||||
|
||||
#endif /* __META_WAYLAND_POINTER_H__ */
|
343
src/wayland/meta-wayland-private.h
Normal file
343
src/wayland/meta-wayland-private.h
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_WAYLAND_PRIVATE_H
|
||||
#define META_WAYLAND_PRIVATE_H
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#include "window-private.h"
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
|
||||
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
|
||||
|
||||
typedef struct _MetaWaylandSeat MetaWaylandSeat;
|
||||
typedef struct _MetaWaylandPointer MetaWaylandPointer;
|
||||
typedef struct _MetaWaylandPointerGrab MetaWaylandPointerGrab;
|
||||
typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface;
|
||||
typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard;
|
||||
typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab;
|
||||
typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface;
|
||||
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
|
||||
typedef struct _MetaWaylandDataSource MetaWaylandDataSource;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
struct wl_signal destroy_signal;
|
||||
struct wl_listener destroy_listener;
|
||||
|
||||
union
|
||||
{
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
|
||||
struct wl_buffer *legacy_buffer;
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS;
|
||||
};
|
||||
|
||||
int32_t width, height;
|
||||
uint32_t busy_count;
|
||||
} MetaWaylandBuffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_listener destroy_listener;
|
||||
} MetaWaylandBufferReference;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
cairo_region_t *region;
|
||||
} MetaWaylandRegion;
|
||||
|
||||
struct _MetaWaylandSurface
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
MetaWaylandCompositor *compositor;
|
||||
guint32 xid;
|
||||
int x;
|
||||
int y;
|
||||
MetaWaylandBufferReference buffer_ref;
|
||||
MetaWindow *window;
|
||||
gboolean has_shell_surface;
|
||||
|
||||
/* All the pending state, that wl_surface.commit will apply. */
|
||||
struct
|
||||
{
|
||||
/* wl_surface.attach */
|
||||
gboolean newly_attached;
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
int32_t sx;
|
||||
int32_t sy;
|
||||
|
||||
/* wl_surface.damage */
|
||||
cairo_region_t *damage;
|
||||
|
||||
/* wl_surface.frame */
|
||||
struct wl_list frame_callback_list;
|
||||
} pending;
|
||||
};
|
||||
|
||||
#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
|
||||
typedef struct _MetaWaylandSurface MetaWaylandSurface;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
struct wl_resource *resource;
|
||||
struct wl_listener surface_destroy_listener;
|
||||
} MetaWaylandShellSurface;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSource source;
|
||||
GPollFD pfd;
|
||||
struct wl_display *display;
|
||||
} WaylandEventSource;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct wl_list link;
|
||||
|
||||
/* Pointer back to the compositor */
|
||||
MetaWaylandCompositor *compositor;
|
||||
|
||||
struct wl_resource *resource;
|
||||
} MetaWaylandFrameCallback;
|
||||
|
||||
struct _MetaWaylandCompositor
|
||||
{
|
||||
struct wl_display *wayland_display;
|
||||
struct wl_event_loop *wayland_loop;
|
||||
GMainLoop *init_loop;
|
||||
ClutterActor *stage;
|
||||
GHashTable *outputs;
|
||||
GSource *wayland_event_source;
|
||||
GList *surfaces;
|
||||
struct wl_list frame_callbacks;
|
||||
|
||||
int xwayland_display_index;
|
||||
char *xwayland_lockfile;
|
||||
int xwayland_abstract_fd;
|
||||
int xwayland_unix_fd;
|
||||
pid_t xwayland_pid;
|
||||
struct wl_client *xwayland_client;
|
||||
struct wl_resource *xserver_resource;
|
||||
|
||||
MetaWaylandSeat *seat;
|
||||
|
||||
/* This surface is only used to keep drag of the implicit grab when
|
||||
synthesizing XEvents for Mutter */
|
||||
MetaWaylandSurface *implicit_grab_surface;
|
||||
/* Button that was pressed to initiate an implicit grab. The
|
||||
implicit grab will only be released when this button is
|
||||
released */
|
||||
guint32 implicit_grab_button;
|
||||
};
|
||||
|
||||
struct _MetaWaylandPointerGrabInterface
|
||||
{
|
||||
void (*focus) (MetaWaylandPointerGrab * grab,
|
||||
MetaWaylandSurface * surface, wl_fixed_t x, wl_fixed_t y);
|
||||
void (*motion) (MetaWaylandPointerGrab * grab,
|
||||
uint32_t time, wl_fixed_t x, wl_fixed_t y);
|
||||
void (*button) (MetaWaylandPointerGrab * grab,
|
||||
uint32_t time, uint32_t button, uint32_t state);
|
||||
};
|
||||
|
||||
struct _MetaWaylandPointerGrab
|
||||
{
|
||||
const MetaWaylandPointerGrabInterface *interface;
|
||||
MetaWaylandPointer *pointer;
|
||||
MetaWaylandSurface *focus;
|
||||
wl_fixed_t x, y;
|
||||
};
|
||||
|
||||
struct _MetaWaylandPointer
|
||||
{
|
||||
struct wl_list resource_list;
|
||||
MetaWaylandSurface *focus;
|
||||
struct wl_resource *focus_resource;
|
||||
struct wl_listener focus_listener;
|
||||
guint32 focus_serial;
|
||||
struct wl_signal focus_signal;
|
||||
|
||||
MetaWaylandPointerGrab *grab;
|
||||
MetaWaylandPointerGrab default_grab;
|
||||
wl_fixed_t grab_x, grab_y;
|
||||
guint32 grab_button;
|
||||
guint32 grab_serial;
|
||||
guint32 grab_time;
|
||||
|
||||
wl_fixed_t x, y;
|
||||
MetaWaylandSurface *current;
|
||||
struct wl_listener current_listener;
|
||||
wl_fixed_t current_x, current_y;
|
||||
|
||||
guint32 button_count;
|
||||
};
|
||||
|
||||
struct _MetaWaylandKeyboardGrabInterface
|
||||
{
|
||||
void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
|
||||
uint32_t key, uint32_t state);
|
||||
void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched,
|
||||
uint32_t mods_locked, uint32_t group);
|
||||
};
|
||||
|
||||
struct _MetaWaylandKeyboardGrab
|
||||
{
|
||||
const MetaWaylandKeyboardGrabInterface *interface;
|
||||
MetaWaylandKeyboard *keyboard;
|
||||
MetaWaylandSurface *focus;
|
||||
uint32_t key;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
int keymap_fd;
|
||||
size_t keymap_size;
|
||||
char *keymap_area;
|
||||
xkb_mod_index_t shift_mod;
|
||||
xkb_mod_index_t caps_mod;
|
||||
xkb_mod_index_t ctrl_mod;
|
||||
xkb_mod_index_t alt_mod;
|
||||
xkb_mod_index_t mod2_mod;
|
||||
xkb_mod_index_t mod3_mod;
|
||||
xkb_mod_index_t super_mod;
|
||||
xkb_mod_index_t mod5_mod;
|
||||
} MetaWaylandXkbInfo;
|
||||
|
||||
struct _MetaWaylandKeyboard
|
||||
{
|
||||
struct wl_list resource_list;
|
||||
MetaWaylandSurface *focus;
|
||||
struct wl_resource *focus_resource;
|
||||
struct wl_listener focus_listener;
|
||||
uint32_t focus_serial;
|
||||
struct wl_signal focus_signal;
|
||||
|
||||
MetaWaylandKeyboardGrab *grab;
|
||||
MetaWaylandKeyboardGrab default_grab;
|
||||
uint32_t grab_key;
|
||||
uint32_t grab_serial;
|
||||
uint32_t grab_time;
|
||||
|
||||
struct wl_array keys;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t mods_depressed;
|
||||
uint32_t mods_latched;
|
||||
uint32_t mods_locked;
|
||||
uint32_t group;
|
||||
} modifiers;
|
||||
|
||||
struct wl_display *display;
|
||||
|
||||
struct xkb_context *xkb_context;
|
||||
|
||||
MetaWaylandXkbInfo xkb_info;
|
||||
struct xkb_rule_names xkb_names;
|
||||
|
||||
MetaWaylandKeyboardGrab input_method_grab;
|
||||
struct wl_resource *input_method_resource;
|
||||
|
||||
ClutterModifierType last_modifier_state;
|
||||
};
|
||||
|
||||
struct _MetaWaylandDataOffer
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
MetaWaylandDataSource *source;
|
||||
struct wl_listener source_destroy_listener;
|
||||
};
|
||||
|
||||
struct _MetaWaylandDataSource
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
struct wl_array mime_types;
|
||||
|
||||
void (*accept) (MetaWaylandDataSource * source,
|
||||
uint32_t serial, const char *mime_type);
|
||||
void (*send) (MetaWaylandDataSource * source,
|
||||
const char *mime_type, int32_t fd);
|
||||
void (*cancel) (MetaWaylandDataSource * source);
|
||||
};
|
||||
|
||||
struct _MetaWaylandSeat
|
||||
{
|
||||
struct wl_list base_resource_list;
|
||||
struct wl_signal destroy_signal;
|
||||
|
||||
uint32_t selection_serial;
|
||||
MetaWaylandDataSource *selection_data_source;
|
||||
struct wl_listener selection_data_source_listener;
|
||||
struct wl_signal selection_signal;
|
||||
|
||||
struct wl_list drag_resource_list;
|
||||
struct wl_client *drag_client;
|
||||
MetaWaylandDataSource *drag_data_source;
|
||||
struct wl_listener drag_data_source_listener;
|
||||
MetaWaylandSurface *drag_focus;
|
||||
struct wl_resource *drag_focus_resource;
|
||||
struct wl_listener drag_focus_listener;
|
||||
MetaWaylandPointerGrab drag_grab;
|
||||
MetaWaylandSurface *drag_surface;
|
||||
struct wl_listener drag_icon_listener;
|
||||
struct wl_signal drag_icon_signal;
|
||||
|
||||
MetaWaylandPointer pointer;
|
||||
MetaWaylandKeyboard keyboard;
|
||||
|
||||
struct wl_display *display;
|
||||
|
||||
MetaCursorTracker *cursor_tracker;
|
||||
MetaWaylandSurface *sprite;
|
||||
int hotspot_x, hotspot_y;
|
||||
struct wl_listener sprite_destroy_listener;
|
||||
|
||||
ClutterActor *current_stage;
|
||||
};
|
||||
|
||||
void meta_wayland_init (void);
|
||||
void meta_wayland_finalize (void);
|
||||
|
||||
/* We maintain a singleton MetaWaylandCompositor which can be got at via this
|
||||
* API after meta_wayland_init() has been called. */
|
||||
MetaWaylandCompositor *meta_wayland_compositor_get_default (void);
|
||||
|
||||
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
|
||||
|
||||
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
void meta_wayland_surface_free (MetaWaylandSurface *surface);
|
||||
|
||||
#endif /* META_WAYLAND_PRIVATE_H */
|
552
src/wayland/meta-wayland-seat.c
Normal file
552
src/wayland/meta-wayland-seat.c
Normal file
@ -0,0 +1,552 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/wayland/clutter-wayland-compositor.h>
|
||||
#include <clutter/wayland/clutter-wayland-surface.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "meta-wayland-seat.h"
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-wayland-keyboard.h"
|
||||
#include "meta-wayland-pointer.h"
|
||||
#include "meta-wayland-data-device.h"
|
||||
#include "meta-window-actor-private.h"
|
||||
#include "meta/meta-shaped-texture.h"
|
||||
#include "meta-shaped-texture-private.h"
|
||||
#include "meta-wayland-stage.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
|
||||
|
||||
static void
|
||||
unbind_resource (struct wl_resource *resource)
|
||||
{
|
||||
wl_list_remove (wl_resource_get_link (resource));
|
||||
}
|
||||
|
||||
static void
|
||||
transform_stage_point_fixed (MetaWaylandSurface *surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
wl_fixed_t *sx,
|
||||
wl_fixed_t *sy)
|
||||
{
|
||||
float xf = 0.0f, yf = 0.0f;
|
||||
|
||||
if (surface->window)
|
||||
{
|
||||
ClutterActor *actor =
|
||||
CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
|
||||
|
||||
if (actor)
|
||||
clutter_actor_transform_stage_point (actor,
|
||||
wl_fixed_to_double (x),
|
||||
wl_fixed_to_double (y),
|
||||
&xf, &yf);
|
||||
}
|
||||
|
||||
*sx = wl_fixed_from_double (xf);
|
||||
*sy = wl_fixed_from_double (yf);
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_unmap_sprite (MetaWaylandSeat *seat)
|
||||
{
|
||||
if (seat->cursor_tracker)
|
||||
{
|
||||
meta_cursor_tracker_set_sprite (seat->cursor_tracker,
|
||||
NULL, 0, 0);
|
||||
|
||||
if (seat->current_stage)
|
||||
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
|
||||
CLUTTER_ACTOR (seat->current_stage));
|
||||
}
|
||||
|
||||
if (seat->sprite)
|
||||
{
|
||||
wl_list_remove (&seat->sprite_destroy_listener.link);
|
||||
seat->sprite = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *context;
|
||||
struct wl_resource *buffer;
|
||||
CoglTexture2D *texture;
|
||||
|
||||
if (seat->cursor_tracker == NULL)
|
||||
return;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
context = clutter_backend_get_cogl_context (backend);
|
||||
buffer = seat->sprite->buffer_ref.buffer->resource;
|
||||
texture = cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL);
|
||||
|
||||
meta_cursor_tracker_set_sprite (seat->cursor_tracker,
|
||||
texture,
|
||||
seat->hotspot_x,
|
||||
seat->hotspot_y);
|
||||
|
||||
if (seat->current_stage)
|
||||
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
|
||||
CLUTTER_ACTOR (seat->current_stage));
|
||||
|
||||
cogl_object_unref (texture);
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_set_cursor (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t serial,
|
||||
struct wl_resource *surface_resource,
|
||||
int32_t x, int32_t y)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
MetaWaylandSurface *surface;
|
||||
|
||||
surface = (surface_resource ?
|
||||
wl_resource_get_user_data (surface_resource) :
|
||||
NULL);
|
||||
|
||||
if (seat->pointer.focus == NULL)
|
||||
return;
|
||||
if (wl_resource_get_client (seat->pointer.focus->resource) != client)
|
||||
return;
|
||||
if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2)
|
||||
return;
|
||||
|
||||
seat->hotspot_x = x;
|
||||
seat->hotspot_y = y;
|
||||
|
||||
if (seat->sprite != surface)
|
||||
{
|
||||
pointer_unmap_sprite (seat);
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
wl_resource_add_destroy_listener (surface->resource,
|
||||
&seat->sprite_destroy_listener);
|
||||
|
||||
seat->sprite = surface;
|
||||
|
||||
if (seat->sprite->buffer_ref.buffer)
|
||||
meta_wayland_seat_update_sprite (seat);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_pointer_interface
|
||||
pointer_interface =
|
||||
{
|
||||
pointer_set_cursor
|
||||
};
|
||||
|
||||
static void
|
||||
seat_get_pointer (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
struct wl_resource *cr;
|
||||
|
||||
cr = wl_client_add_object (client, &wl_pointer_interface,
|
||||
&pointer_interface, id, seat);
|
||||
wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr));
|
||||
wl_resource_set_destructor (cr, unbind_resource);
|
||||
|
||||
if (seat->pointer.focus &&
|
||||
wl_resource_get_client (seat->pointer.focus->resource) == client)
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
wl_fixed_t sx, sy;
|
||||
|
||||
surface = (MetaWaylandSurface *) seat->pointer.focus;
|
||||
transform_stage_point_fixed (surface,
|
||||
seat->pointer.x,
|
||||
seat->pointer.y,
|
||||
&sx, &sy);
|
||||
meta_wayland_pointer_set_focus (&seat->pointer,
|
||||
seat->pointer.focus,
|
||||
sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seat_get_keyboard (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
struct wl_resource *cr;
|
||||
|
||||
cr = wl_client_add_object (client, &wl_keyboard_interface, NULL, id, seat);
|
||||
wl_list_insert (&seat->keyboard.resource_list, wl_resource_get_link (cr));
|
||||
wl_resource_set_destructor (cr, unbind_resource);
|
||||
|
||||
wl_keyboard_send_keymap (cr,
|
||||
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
|
||||
seat->keyboard.xkb_info.keymap_fd,
|
||||
seat->keyboard.xkb_info.keymap_size);
|
||||
|
||||
if (seat->keyboard.focus &&
|
||||
wl_resource_get_client (seat->keyboard.focus->resource) == client)
|
||||
{
|
||||
meta_wayland_keyboard_set_focus (&seat->keyboard,
|
||||
seat->keyboard.focus);
|
||||
meta_wayland_data_device_set_keyboard_focus (seat);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seat_get_touch (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id)
|
||||
{
|
||||
/* Touch not supported */
|
||||
}
|
||||
|
||||
static const struct wl_seat_interface
|
||||
seat_interface =
|
||||
{
|
||||
seat_get_pointer,
|
||||
seat_get_keyboard,
|
||||
seat_get_touch
|
||||
};
|
||||
|
||||
static void
|
||||
bind_seat (struct wl_client *client,
|
||||
void *data,
|
||||
guint32 version,
|
||||
guint32 id)
|
||||
{
|
||||
MetaWaylandSeat *seat = data;
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = wl_client_add_object (client,
|
||||
&wl_seat_interface,
|
||||
&seat_interface,
|
||||
id,
|
||||
data);
|
||||
wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource));
|
||||
wl_resource_set_destructor (resource, unbind_resource);
|
||||
|
||||
wl_seat_send_capabilities (resource,
|
||||
WL_SEAT_CAPABILITY_POINTER |
|
||||
WL_SEAT_CAPABILITY_KEYBOARD);
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaWaylandSeat *seat =
|
||||
wl_container_of (listener, seat, sprite_destroy_listener);
|
||||
|
||||
pointer_unmap_sprite (seat);
|
||||
}
|
||||
|
||||
MetaWaylandSeat *
|
||||
meta_wayland_seat_new (struct wl_display *display)
|
||||
{
|
||||
MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
|
||||
|
||||
wl_signal_init (&seat->destroy_signal);
|
||||
|
||||
seat->selection_data_source = NULL;
|
||||
wl_list_init (&seat->base_resource_list);
|
||||
wl_signal_init (&seat->selection_signal);
|
||||
wl_list_init (&seat->drag_resource_list);
|
||||
wl_signal_init (&seat->drag_icon_signal);
|
||||
|
||||
meta_wayland_pointer_init (&seat->pointer);
|
||||
|
||||
meta_wayland_keyboard_init (&seat->keyboard, display);
|
||||
|
||||
seat->display = display;
|
||||
|
||||
seat->current_stage = 0;
|
||||
|
||||
seat->sprite = NULL;
|
||||
seat->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
|
||||
seat->hotspot_x = 16;
|
||||
seat->hotspot_y = 16;
|
||||
|
||||
wl_display_add_global (display, &wl_seat_interface, seat, bind_seat);
|
||||
|
||||
return seat;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_motion (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaWaylandPointer *pointer = &seat->pointer;
|
||||
float x, y;
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
pointer->x = wl_fixed_from_double (x);
|
||||
pointer->y = wl_fixed_from_double (y);
|
||||
|
||||
meta_wayland_seat_repick (seat,
|
||||
clutter_event_get_time (event),
|
||||
clutter_event_get_source (event));
|
||||
|
||||
pointer->grab->interface->motion (pointer->grab,
|
||||
clutter_event_get_time (event),
|
||||
pointer->grab->x,
|
||||
pointer->grab->y);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_motion_event (MetaWaylandSeat *seat,
|
||||
const ClutterMotionEvent *event)
|
||||
{
|
||||
notify_motion (seat, (const ClutterEvent *) event);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_button_event (MetaWaylandSeat *seat,
|
||||
const ClutterButtonEvent *event)
|
||||
{
|
||||
MetaWaylandPointer *pointer = &seat->pointer;
|
||||
gboolean state = event->type == CLUTTER_BUTTON_PRESS;
|
||||
uint32_t button;
|
||||
|
||||
notify_motion (seat, (const ClutterEvent *) event);
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
/* The evdev input right and middle button numbers are swapped
|
||||
relative to how Clutter numbers them */
|
||||
case 2:
|
||||
button = BTN_MIDDLE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
button = BTN_RIGHT;
|
||||
break;
|
||||
|
||||
default:
|
||||
button = event->button + BTN_LEFT - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (state)
|
||||
{
|
||||
if (pointer->button_count == 0)
|
||||
{
|
||||
MetaWaylandSurface *surface = pointer->current;
|
||||
|
||||
pointer->grab_button = button;
|
||||
pointer->grab_time = event->time;
|
||||
pointer->grab_x = pointer->x;
|
||||
pointer->grab_y = pointer->y;
|
||||
|
||||
if (button == BTN_LEFT &&
|
||||
surface &&
|
||||
surface->window &&
|
||||
surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
meta_window_raise (surface->window);
|
||||
}
|
||||
}
|
||||
|
||||
pointer->button_count++;
|
||||
}
|
||||
else
|
||||
pointer->button_count--;
|
||||
|
||||
pointer->grab->interface->button (pointer->grab, event->time, button, state);
|
||||
|
||||
if (pointer->button_count == 1)
|
||||
pointer->grab_serial = wl_display_get_serial (seat->display);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_scroll_event (MetaWaylandSeat *seat,
|
||||
const ClutterScrollEvent *event)
|
||||
{
|
||||
enum wl_pointer_axis axis;
|
||||
wl_fixed_t value;
|
||||
|
||||
notify_motion (seat, (const ClutterEvent *) event);
|
||||
|
||||
switch (event->direction)
|
||||
{
|
||||
case CLUTTER_SCROLL_UP:
|
||||
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
|
||||
value = -DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_DOWN:
|
||||
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
|
||||
value = DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_LEFT:
|
||||
axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
|
||||
value = -DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_RIGHT:
|
||||
axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
|
||||
value = DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (seat->pointer.focus_resource)
|
||||
wl_pointer_send_axis (seat->pointer.focus_resource,
|
||||
event->time,
|
||||
axis,
|
||||
value);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_MOTION:
|
||||
handle_motion_event (seat,
|
||||
(const ClutterMotionEvent *) event);
|
||||
break;
|
||||
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
handle_button_event (seat,
|
||||
(const ClutterButtonEvent *) event);
|
||||
break;
|
||||
|
||||
case CLUTTER_KEY_PRESS:
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
meta_wayland_keyboard_handle_event (&seat->keyboard,
|
||||
(const ClutterKeyEvent *) event);
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL:
|
||||
handle_scroll_event (seat, (const ClutterScrollEvent *) event);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_pointer_position_for_actor (MetaWaylandPointer *pointer,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
float ax, ay;
|
||||
|
||||
clutter_actor_transform_stage_point (actor,
|
||||
wl_fixed_to_double (pointer->x),
|
||||
wl_fixed_to_double (pointer->y),
|
||||
&ax, &ay);
|
||||
pointer->current_x = wl_fixed_from_double (ax);
|
||||
pointer->current_y = wl_fixed_from_double (ay);
|
||||
}
|
||||
|
||||
/* The actor argument can be NULL in which case a Clutter pick will be
|
||||
performed to determine the right actor. An actor should only be
|
||||
passed if the repick is being performed due to an event in which
|
||||
case Clutter will have already performed a pick so we can avoid
|
||||
redundantly doing another one */
|
||||
void
|
||||
meta_wayland_seat_repick (MetaWaylandSeat *seat,
|
||||
uint32_t time,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
MetaWaylandPointer *pointer = &seat->pointer;
|
||||
MetaWaylandSurface *surface = NULL;
|
||||
|
||||
if (actor == NULL && seat->current_stage)
|
||||
{
|
||||
ClutterStage *stage = CLUTTER_STAGE (seat->current_stage);
|
||||
actor = clutter_stage_get_actor_at_pos (stage,
|
||||
CLUTTER_PICK_REACTIVE,
|
||||
wl_fixed_to_double (pointer->x),
|
||||
wl_fixed_to_double (pointer->y));
|
||||
}
|
||||
|
||||
if (actor)
|
||||
seat->current_stage = clutter_actor_get_stage (actor);
|
||||
else
|
||||
seat->current_stage = NULL;
|
||||
|
||||
if (META_IS_WINDOW_ACTOR (actor))
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
|
||||
|
||||
update_pointer_position_for_actor (pointer, actor);
|
||||
|
||||
surface = window->surface;
|
||||
}
|
||||
else if (META_IS_SHAPED_TEXTURE (actor))
|
||||
{
|
||||
MetaShapedTexture *shaped_texture = META_SHAPED_TEXTURE (actor);
|
||||
|
||||
update_pointer_position_for_actor (pointer, actor);
|
||||
|
||||
surface = meta_shaped_texture_get_wayland_surface (shaped_texture);
|
||||
}
|
||||
|
||||
pointer->current = surface;
|
||||
if (surface != pointer->focus)
|
||||
{
|
||||
const MetaWaylandPointerGrabInterface *interface =
|
||||
pointer->grab->interface;
|
||||
interface->focus (pointer->grab,
|
||||
surface,
|
||||
pointer->current_x, pointer->current_y);
|
||||
}
|
||||
|
||||
if (pointer->grab->focus)
|
||||
transform_stage_point_fixed (pointer->grab->focus,
|
||||
pointer->x,
|
||||
pointer->y,
|
||||
&pointer->grab->x,
|
||||
&pointer->grab->y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_seat_free (MetaWaylandSeat *seat)
|
||||
{
|
||||
pointer_unmap_sprite (seat);
|
||||
|
||||
meta_wayland_pointer_release (&seat->pointer);
|
||||
meta_wayland_keyboard_release (&seat->keyboard);
|
||||
|
||||
wl_signal_emit (&seat->destroy_signal, seat);
|
||||
|
||||
g_slice_free (MetaWaylandSeat, seat);
|
||||
}
|
50
src/wayland/meta-wayland-seat.h
Normal file
50
src/wayland/meta-wayland-seat.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __META_WAYLAND_SEAT_H__
|
||||
#define __META_WAYLAND_SEAT_H__
|
||||
|
||||
#include <wayland-server.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
MetaWaylandSeat *
|
||||
meta_wayland_seat_new (struct wl_display *display);
|
||||
|
||||
void
|
||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event);
|
||||
|
||||
void
|
||||
meta_wayland_seat_repick (MetaWaylandSeat *seat,
|
||||
uint32_t time,
|
||||
ClutterActor *actor);
|
||||
|
||||
void
|
||||
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat);
|
||||
|
||||
void
|
||||
meta_wayland_seat_free (MetaWaylandSeat *seat);
|
||||
|
||||
#endif /* __META_WAYLAND_SEAT_H__ */
|
67
src/wayland/meta-wayland-stage.c
Normal file
67
src/wayland/meta-wayland-stage.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
|
||||
#include "meta-wayland-stage.h"
|
||||
#include "meta/meta-window-actor.h"
|
||||
#include "meta/meta-shaped-texture.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE);
|
||||
|
||||
static void
|
||||
meta_wayland_stage_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaWaylandCompositor *compositor;
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->paint (actor);
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
if (compositor->seat->cursor_tracker)
|
||||
meta_cursor_tracker_paint (compositor->seat->cursor_tracker);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_stage_class_init (MetaWaylandStageClass *klass)
|
||||
{
|
||||
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
|
||||
|
||||
actor_class->paint = meta_wayland_stage_paint;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_stage_init (MetaWaylandStage *self)
|
||||
{
|
||||
clutter_stage_set_user_resizable (CLUTTER_STAGE (self), FALSE);
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
meta_wayland_stage_new (void)
|
||||
{
|
||||
return g_object_new (META_WAYLAND_TYPE_STAGE,
|
||||
"cursor-visible", FALSE,
|
||||
NULL);
|
||||
}
|
70
src/wayland/meta-wayland-stage.h
Normal file
70
src/wayland/meta-wayland-stage.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_WAYLAND_STAGE_H
|
||||
#define META_WAYLAND_STAGE_H
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "window-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_WAYLAND_TYPE_STAGE \
|
||||
(meta_wayland_stage_get_type())
|
||||
#define META_WAYLAND_STAGE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||
META_WAYLAND_TYPE_STAGE, \
|
||||
MetaWaylandStage))
|
||||
#define META_WAYLAND_STAGE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||
META_WAYLAND_TYPE_STAGE, \
|
||||
MetaWaylandStageClass))
|
||||
#define META_WAYLAND_IS_STAGE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||
META_WAYLAND_TYPE_STAGE))
|
||||
#define META_WAYLAND_IS_STAGE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
META_WAYLAND_TYPE_STAGE))
|
||||
#define META_WAYLAND_STAGE_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||
META_WAYLAND_STAGE, \
|
||||
MetaWaylandStageClass))
|
||||
|
||||
typedef struct _MetaWaylandStage MetaWaylandStage;
|
||||
typedef struct _MetaWaylandStageClass MetaWaylandStageClass;
|
||||
|
||||
struct _MetaWaylandStageClass
|
||||
{
|
||||
ClutterStageClass parent_class;
|
||||
};
|
||||
|
||||
struct _MetaWaylandStage
|
||||
{
|
||||
ClutterStage parent;
|
||||
};
|
||||
|
||||
GType meta_wayland_stage_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *meta_wayland_stage_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_WAYLAND_STAGE_H */
|
1650
src/wayland/meta-wayland.c
Normal file
1650
src/wayland/meta-wayland.c
Normal file
File diff suppressed because it is too large
Load Diff
36
src/wayland/meta-xwayland-private.h
Normal file
36
src/wayland/meta-xwayland-private.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_XWAYLAND_PRIVATE_H
|
||||
#define META_XWAYLAND_PRIVATE_H
|
||||
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
gboolean
|
||||
meta_xwayland_start (MetaWaylandCompositor *compositor);
|
||||
|
||||
void
|
||||
meta_xwayland_complete_init (void);
|
||||
|
||||
void
|
||||
meta_xwayland_stop (MetaWaylandCompositor *compositor);
|
||||
|
||||
#endif /* META_XWAYLAND_PRIVATE_H */
|
461
src/wayland/meta-xwayland.c
Normal file
461
src/wayland/meta-xwayland.c
Normal file
@ -0,0 +1,461 @@
|
||||
/*
|
||||
* X Wayland Support
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "meta-xwayland-private.h"
|
||||
#include "meta-window-actor-private.h"
|
||||
#include "xserver-server-protocol.h"
|
||||
|
||||
static void
|
||||
xserver_set_window_id (struct wl_client *client,
|
||||
struct wl_resource *compositor_resource,
|
||||
struct wl_resource *surface_resource,
|
||||
guint32 xid)
|
||||
{
|
||||
MetaWaylandCompositor *compositor =
|
||||
wl_resource_get_user_data (compositor_resource);
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaWindow *window;
|
||||
|
||||
g_return_if_fail (surface->xid == None);
|
||||
|
||||
surface->xid = xid;
|
||||
|
||||
window = meta_display_lookup_x_window (display, xid);
|
||||
if (window)
|
||||
{
|
||||
MetaWindowActor *window_actor =
|
||||
META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
|
||||
meta_window_actor_set_wayland_surface (window_actor, surface);
|
||||
|
||||
surface->window = window;
|
||||
window->surface = surface;
|
||||
|
||||
/* If the window is already meant to have focus then the
|
||||
* original attempt to call this in response to the FocusIn
|
||||
* event will have been lost because there was no surface
|
||||
* yet. */
|
||||
if (window->has_focus)
|
||||
meta_wayland_compositor_set_input_focus (compositor, window);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xserver_interface xserver_implementation = {
|
||||
xserver_set_window_id
|
||||
};
|
||||
|
||||
static void
|
||||
bind_xserver (struct wl_client *client,
|
||||
void *data,
|
||||
guint32 version,
|
||||
guint32 id)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = data;
|
||||
|
||||
/* If it's a different client than the xserver we launched,
|
||||
* don't start the wm. */
|
||||
if (client != compositor->xwayland_client)
|
||||
return;
|
||||
|
||||
compositor->xserver_resource =
|
||||
wl_resource_create (client, &xserver_interface, version, id);
|
||||
wl_resource_set_implementation (compositor->xserver_resource,
|
||||
&xserver_implementation, compositor, NULL);
|
||||
|
||||
wl_resource_post_event (compositor->xserver_resource,
|
||||
XSERVER_LISTEN_SOCKET,
|
||||
compositor->xwayland_abstract_fd);
|
||||
|
||||
wl_resource_post_event (compositor->xserver_resource,
|
||||
XSERVER_LISTEN_SOCKET,
|
||||
compositor->xwayland_unix_fd);
|
||||
|
||||
/* Make sure xwayland will recieve the above sockets in a finite
|
||||
* time before unblocking the initialization mainloop since we are
|
||||
* then going to immediately try and connect to those as the window
|
||||
* manager. */
|
||||
wl_client_flush (client);
|
||||
|
||||
/* At this point xwayland is all setup to start accepting
|
||||
* connections so we can quit the transient initialization mainloop
|
||||
* and unblock meta_wayland_init() to continue initializing mutter.
|
||||
* */
|
||||
g_main_loop_quit (compositor->init_loop);
|
||||
compositor->init_loop = NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
create_lockfile (int display, int *display_out)
|
||||
{
|
||||
char *filename;
|
||||
int size;
|
||||
char pid[11];
|
||||
int fd;
|
||||
|
||||
do
|
||||
{
|
||||
char *end;
|
||||
pid_t other;
|
||||
|
||||
filename = g_strdup_printf ("/tmp/.X%d-lock", display);
|
||||
fd = open (filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
|
||||
|
||||
if (fd < 0 && errno == EEXIST)
|
||||
{
|
||||
fd = open (filename, O_CLOEXEC, O_RDONLY);
|
||||
if (fd < 0 || read (fd, pid, 11) != 11)
|
||||
{
|
||||
const char *msg = strerror (errno);
|
||||
g_warning ("can't read lock file %s: %s", filename, msg);
|
||||
g_free (filename);
|
||||
|
||||
/* ignore error and try the next display number */
|
||||
display++;
|
||||
continue;
|
||||
}
|
||||
close (fd);
|
||||
|
||||
other = strtol (pid, &end, 0);
|
||||
if (end != pid + 10)
|
||||
{
|
||||
g_warning ("can't parse lock file %s", filename);
|
||||
g_free (filename);
|
||||
|
||||
/* ignore error and try the next display number */
|
||||
display++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kill (other, 0) < 0 && errno == ESRCH)
|
||||
{
|
||||
g_warning ("unlinking stale lock file %s", filename);
|
||||
if (unlink (filename) < 0)
|
||||
{
|
||||
const char *msg = strerror (errno);
|
||||
g_warning ("failed to unlink stale lock file: %s", msg);
|
||||
display++;
|
||||
}
|
||||
g_free (filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
display++;
|
||||
continue;
|
||||
}
|
||||
else if (fd < 0)
|
||||
{
|
||||
const char *msg = strerror (errno);
|
||||
g_warning ("failed to create lock file %s: %s", filename , msg);
|
||||
g_free (filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
/* Subtle detail: we use the pid of the wayland compositor, not the xserver
|
||||
* in the lock file. */
|
||||
size = snprintf (pid, 11, "%10d\n", getpid ());
|
||||
if (size != 11 || write (fd, pid, 11) != 11)
|
||||
{
|
||||
unlink (filename);
|
||||
close (fd);
|
||||
g_warning ("failed to write pid to lock file %s", filename);
|
||||
g_free (filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
*display_out = display;
|
||||
return filename;
|
||||
}
|
||||
|
||||
static int
|
||||
bind_to_abstract_socket (int display)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size, name_size;
|
||||
int fd;
|
||||
|
||||
fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
|
||||
"%c/tmp/.X11-unix/X%d", 0, display);
|
||||
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
||||
if (bind (fd, (struct sockaddr *) &addr, size) < 0)
|
||||
{
|
||||
g_warning ("failed to bind to @%s: %s\n",
|
||||
addr.sun_path + 1, strerror (errno));
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (fd, 1) < 0)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
bind_to_unix_socket (int display)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size, name_size;
|
||||
int fd;
|
||||
|
||||
fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
addr.sun_family = AF_LOCAL;
|
||||
name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
|
||||
"/tmp/.X11-unix/X%d", display) + 1;
|
||||
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
||||
unlink (addr.sun_path);
|
||||
if (bind (fd, (struct sockaddr *) &addr, size) < 0)
|
||||
{
|
||||
char *msg = strerror (errno);
|
||||
g_warning ("failed to bind to %s (%s)\n", addr.sun_path, msg);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (fd, 1) < 0) {
|
||||
unlink (addr.sun_path);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
uncloexec_and_setpgid (gpointer user_data)
|
||||
{
|
||||
int fd = GPOINTER_TO_INT (user_data);
|
||||
|
||||
/* Make sure the client end of the socket pair doesn't get closed
|
||||
* when we exec xwayland. */
|
||||
int flags = fcntl (fd, F_GETFD);
|
||||
if (flags != -1)
|
||||
fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC);
|
||||
|
||||
/* Put this process in a background process group, so that Ctrl-C
|
||||
goes to mutter only */
|
||||
setpgid (0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
xserver_died (GPid pid,
|
||||
gint status,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!WIFEXITED (status))
|
||||
g_error ("X Wayland crashed; aborting");
|
||||
else
|
||||
{
|
||||
/* For now we simply abort if we see the server exit.
|
||||
*
|
||||
* In the future X will only be loaded lazily for legacy X support
|
||||
* but for now it's a hard requirement. */
|
||||
g_error ("Spurious exit of X Wayland server");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
x_io_error (Display *display)
|
||||
{
|
||||
g_error ("Connection to xwayland lost");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_xwayland_start (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
int display = 0;
|
||||
char *lockfile = NULL;
|
||||
int sp[2];
|
||||
pid_t pid;
|
||||
char **env;
|
||||
char *fd_string;
|
||||
char *display_name;
|
||||
char *args[11];
|
||||
GError *error;
|
||||
|
||||
wl_global_create (compositor->wayland_display,
|
||||
&xserver_interface, 1,
|
||||
compositor, bind_xserver);
|
||||
|
||||
do
|
||||
{
|
||||
lockfile = create_lockfile (display, &display);
|
||||
if (!lockfile)
|
||||
{
|
||||
g_warning ("Failed to create an X lock file");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
compositor->xwayland_abstract_fd = bind_to_abstract_socket (display);
|
||||
if (compositor->xwayland_abstract_fd < 0)
|
||||
{
|
||||
unlink (lockfile);
|
||||
|
||||
if (errno == EADDRINUSE)
|
||||
{
|
||||
display++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
compositor->xwayland_unix_fd = bind_to_unix_socket (display);
|
||||
if (compositor->xwayland_abstract_fd < 0)
|
||||
{
|
||||
unlink (lockfile);
|
||||
close (compositor->xwayland_abstract_fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
compositor->xwayland_display_index = display;
|
||||
compositor->xwayland_lockfile = lockfile;
|
||||
|
||||
/* We want xwayland to be a wayland client so we make a socketpair to setup a
|
||||
* wayland protocol connection. */
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sp) < 0)
|
||||
{
|
||||
g_warning ("socketpair failed\n");
|
||||
unlink (lockfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
env = g_get_environ ();
|
||||
fd_string = g_strdup_printf ("%d", sp[1]);
|
||||
env = g_environ_setenv (env, "WAYLAND_SOCKET", fd_string, TRUE);
|
||||
g_free (fd_string);
|
||||
|
||||
display_name = g_strdup_printf (":%d",
|
||||
compositor->xwayland_display_index);
|
||||
|
||||
args[0] = XWAYLAND_PATH;
|
||||
args[1] = display_name;
|
||||
args[2] = "-wayland";
|
||||
args[3] = "-rootless";
|
||||
args[4] = "-retro";
|
||||
args[5] = "-noreset";
|
||||
args[6] = "-logfile";
|
||||
args[7] = g_build_filename (g_get_user_cache_dir (), "xwayland.log", NULL);
|
||||
args[8] = "-nolisten";
|
||||
args[9] = "all";
|
||||
args[10] = NULL;
|
||||
|
||||
error = NULL;
|
||||
if (g_spawn_async (NULL, /* cwd */
|
||||
args,
|
||||
env,
|
||||
G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
|
||||
G_SPAWN_DO_NOT_REAP_CHILD |
|
||||
G_SPAWN_STDOUT_TO_DEV_NULL |
|
||||
G_SPAWN_STDERR_TO_DEV_NULL,
|
||||
uncloexec_and_setpgid,
|
||||
GINT_TO_POINTER (sp[1]),
|
||||
&pid,
|
||||
&error))
|
||||
{
|
||||
g_message ("forked X server, pid %d\n", pid);
|
||||
|
||||
close (sp[1]);
|
||||
compositor->xwayland_client =
|
||||
wl_client_create (compositor->wayland_display, sp[0]);
|
||||
|
||||
compositor->xwayland_pid = pid;
|
||||
g_child_watch_add (pid, xserver_died, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_error ("Failed to fork for xwayland server: %s", error->message);
|
||||
}
|
||||
|
||||
g_strfreev (env);
|
||||
g_free (display_name);
|
||||
|
||||
/* We need to run a mainloop until we know xwayland has a binding
|
||||
* for our xserver interface at which point we can assume it's
|
||||
* ready to start accepting connections. */
|
||||
compositor->init_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
g_main_loop_run (compositor->init_loop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* To be called right after connecting */
|
||||
void
|
||||
meta_xwayland_complete_init (void)
|
||||
{
|
||||
/* We install an X IO error handler in addition to the child watch,
|
||||
because after Xlib connects our child watch may not be called soon
|
||||
enough, and therefore we won't crash when X exits (and most important
|
||||
we won't reset the tty).
|
||||
*/
|
||||
XSetIOErrorHandler (x_io_error);
|
||||
}
|
||||
|
||||
void
|
||||
meta_xwayland_stop (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
char path[256];
|
||||
|
||||
snprintf (path, sizeof path, "/tmp/.X%d-lock",
|
||||
compositor->xwayland_display_index);
|
||||
unlink (path);
|
||||
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d",
|
||||
compositor->xwayland_display_index);
|
||||
unlink (path);
|
||||
|
||||
unlink (compositor->xwayland_lockfile);
|
||||
}
|
@ -205,11 +205,14 @@
|
||||
|
||||
Changes the backlight of @output to @value, which is
|
||||
expressed as a percentage and rounded to the HW limits.
|
||||
|
||||
Returns the new value after rounding.
|
||||
-->
|
||||
<method name="ChangeBacklight">
|
||||
<arg name="serial" direction="in" type="u" />
|
||||
<arg name="output" direction="in" type="u" />
|
||||
<arg name="value" direction="in" type="i" />
|
||||
<arg name="new_value" direction="out" type="i" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
@ -277,5 +280,14 @@
|
||||
XRandR interface directly).
|
||||
-->
|
||||
<property name="PowerSaveMode" type="i" access="readwrite" />
|
||||
|
||||
<!--
|
||||
MonitorsChanged:
|
||||
|
||||
The signal is emitted every time the screen configuration
|
||||
changes.
|
||||
The client should then call GetResources() to read the new layout.
|
||||
-->
|
||||
<signal name="MonitorsChanged" />
|
||||
</interface>
|
||||
</node>
|
||||
|
Reference in New Issue
Block a user