Compare commits

..

2 Commits

Author SHA1 Message Date
b9d798c213 cursor-tracker: Properly handle invisible cursors
We might be asked to not display the cursor ourselves but we should
still emit cursor-changed signals and hand out the correct sprite and
hot point information when asked so that consumers can still draw an
updated cursor themselves.

This fixes the cursor not showing up in gnome-shell's zoom mode.
2014-04-07 19:23:35 +02:00
5abf41ab5a split cursor_tracker 2014-04-07 19:20:14 +02:00
219 changed files with 37560 additions and 25657 deletions

10
.gitignore vendored
View File

@ -22,7 +22,7 @@ missing
src/50-mutter-navigation.xml
src/50-mutter-system.xml
src/50-mutter-windows.xml
src/mutter.desktop
src/mutter-wm.desktop
src/mutter-wayland.desktop
*.o
*.a
@ -46,8 +46,9 @@ POTFILES
po/*.pot
50-metacity-desktop-key.xml
50-metacity-key.xml
libmutter.pc
mutter
libmutter-wayland.pc
mutter-wayland
mutter-launch
org.gnome.mutter.gschema.valid
org.gnome.mutter.gschema.xml
org.gnome.mutter.wayland.gschema.valid
@ -55,7 +56,6 @@ org.gnome.mutter.wayland.gschema.xml
testasyncgetprop
testboxes
testgradient
m4/*
mutter-grayscale
mutter-mag
mutter-message
@ -77,7 +77,7 @@ src/mutter-marshal.[ch]
src/stamp-mutter-marshal.h
src/meta-dbus-display-config.[ch]
src/meta-dbus-idle-monitor.[ch]
src/meta-dbus-login1.[ch]
src/mutter-plugins.pc
src/gtk-shell-protocol.c
src/gtk-shell-server-protocol.h
src/xdg-shell-protocol.c

View File

@ -1,8 +1,6 @@
SUBDIRS=src po doc
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc

48
NEWS
View File

@ -1,51 +1,3 @@
3.13.2
======
* Add basic HiDPI support on wayland [Adel; #728902]
* Fix crash when monitors change during suspend [Giovanni; #725637]
* Replace mutter-launch with logind integration [Jasper; #724604]
* Move window menu into the compositor [Jasper; #726352]
* Fix delayed focus-follows-mouse support [Florian; #730541]
* Support fallback app menu in window decorations [Florian; #730752]
* Misc. bug fixes and cleanups [Giovanni, Jonas, Jasper; #729732, #729602,
#726714]
Contributors:
Jonas Ådahl, Giovanni Campagna, Adel Gadllah, Florian Müllner,
Jasper St. Pierre, Rico Tzschichholz
Translations:
Pau Iranzo [ca], Daniel Mustieles [es]
3.13.1
======
* Fix opacity values from _NET_WM_WINDOW_OPACITY [Nirbheek; #727874]
* Merge wayland branch [Jasper, Giovanni, Robert B., Neil, Adel, Rui, Jonas,
Lionel, Tim, Owen, Florian, Colin W., Cosimo, Ray, Kalev, Pavel, Robert A.,
Magdalen, Marek, Matthias, Alban, Seán, Daniel, Stefano, Carlos, Colin G.,
Andreas, Alexander, Ryan, Marc-André, Asad, Alberto, Bastien, Hans,
Debarshi, Sindhu, Andika, Rico, Olav]
* Don't prevent workspace switches for present_with_time() [Florian; #728018]
* Add shortcuts for switching to the last workspace [Elad; #659288]
* Make move/resize menu items behave like the keybindings [Jasper; #728617]
* Misc. bug fixes and cleanups [Jasper, Bastien, Florian, Adel; #720631,
#727979, #728423, #728395, #729044]
Contributors:
Jonas Ådahl, Elad Alfassa, Robert Ancell, Magdalen Berns, Robert Bragg,
Giovanni Campagna, Cosimo Cecchi, Marek Chalupa, Nirbheek Chauhan,
Matthias Clasen, Alban Crequy, Seán de Búrca, Daniel Drake, Jason Ekstrand,
Stefano Facchini, Adel Gadllah, Carlos Garnacho, Colin Guthrie,
Andreas Heider, Lionel Landwerlin, Alexander Larsson, Kalev Lember,
Ryan Lortie, Tim Lunn, Marc-André Lureau, Rui Matos, Asad Mehmood,
Alberto Milone, Florian Müllner, Bastien Nocera, Hans Petter Jansson,
Debarshi Ray, Neil Roberts, Sindhu S, Jasper St. Pierre, Ray Strode,
Andika Triwidada, Rico Tzschichholz, Pavel Vasin, Olav Vitters,
Colin Walters, A. Walton, Owen W. Taylor
Translations:
Inaki Larranaga Murgoitio [eu], marablack3 [el], Daniel Mustieles [es],
Fran Diéguez [gl], Yosef Or Boczko [he], Dirgita [id]
3.12.0
======
* Fix grab issue with SSD xwayland windows [Rui; #726123]

View File

@ -2,8 +2,8 @@ AC_PREREQ(2.50)
AC_CONFIG_MACRO_DIR([m4])
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [13])
m4_define([mutter_micro_version], [2])
m4_define([mutter_minor_version], [12])
m4_define([mutter_micro_version], [0])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -13,7 +13,6 @@ m4_define([mutter_plugin_api_version], [3])
AC_INIT([mutter], [mutter_version],
[http://bugzilla.gnome.org/enter_bug.cgi?product=mutter])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR(src/core/display.c)
AC_CONFIG_HEADERS(config.h)
@ -21,6 +20,10 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar subdir-objects])
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
@ -36,7 +39,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])
@ -69,12 +72,12 @@ CANBERRA_GTK_VERSION=0.26
CLUTTER_PACKAGE=clutter-1.0
MUTTER_PC_MODULES="
gtk+-3.0 >= 3.9.11
gtk+-3.0 >= 3.3.7
gio-2.0 >= 2.25.10
pango >= 1.2.0
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
xcomposite >= 0.2 xfixes xext xdamage xi >= 1.6.0
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.17.5
cogl-1.0 >= 1.17.1
upower-glib >= 0.99.0
@ -117,16 +120,27 @@ 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/Xwayland"])
[XWAYLAND_PATH="$bindir/Xorg"])
AM_GLIB_GNU_GETTEXT
## here we get the flags we'll actually use
# GRegex requires Glib-2.14.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
# Unconditionally use this dir to avoid a circular dep with gnomecc
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
@ -199,7 +213,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_SUBST([WAYLAND_SCANNER])
AC_SUBST(XWAYLAND_PATH)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server >= 1.4.93 libdrm libsystemd"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm"
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
@ -238,6 +252,28 @@ if test x$have_xinerama = xno; then
AC_MSG_ERROR([Xinerama extension was not found])
fi
SHAPE_LIBS=
found_shape=no
AC_CHECK_LIB(Xext, XShapeQueryExtension,
[AC_CHECK_HEADER(X11/extensions/shape.h,
SHAPE_LIBS=-lXext found_shape=yes)],
, $ALL_X_LIBS)
if test x$enable_shape = xno; then
found_shape=no
fi
if test x$enable_shape = xyes; then
if test "$found_shape" = "no"; then
AC_MSG_ERROR([--enable-shape forced and Shape not found])
exit 1
fi
fi
if test "x$found_shape" = "xyes"; then
AC_DEFINE(HAVE_SHAPE, , [Have the shape extension library])
fi
found_xkb=no
AC_CHECK_LIB(X11, XkbQueryExtension,
[AC_CHECK_HEADER(X11/XKBlib.h,
@ -255,13 +291,37 @@ AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
[AC_CHECK_HEADER(X11/extensions/Xrandr.h,
RANDR_LIBS=-lXrandr found_randr=yes,,
[#include <X11/Xlib.h>])],
, -lXext $ALL_X_LIBS)
, -lXrender -lXext $ALL_X_LIBS)
if test "x$found_randr" = "xyes"; then
AC_DEFINE(HAVE_RANDR, , [Have the Xrandr extension library])
fi
MUTTER_LIBS="$MUTTER_LIBS $RANDR_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
XSYNC_LIBS=
found_xsync=no
AC_CHECK_LIB(Xext, XSyncQueryExtension,
[AC_CHECK_HEADER(X11/extensions/sync.h,
found_xsync=yes,,
[#include <X11/Xlib.h>])],
, $ALL_X_LIBS)
if test x$enable_xsync = xno; then
found_xsync=no
fi
if test x$enable_xsync = xyes; then
if test "$found_xsync" = "no"; then
AC_MSG_ERROR([--enable-xsync forced and XSync not found])
exit 1
fi
fi
if test "x$found_xsync" = "xyes"; then
XSYNC_LIBS=-lXext
AC_DEFINE(HAVE_XSYNC, , [Have the Xsync extension library])
fi
MUTTER_LIBS="$MUTTER_LIBS $XSYNC_LIBS $RANDR_LIBS $SHAPE_LIBS $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm"
found_sm=no
case "$MUTTER_LIBS" in
@ -391,7 +451,7 @@ doc/man/Makefile
doc/reference/Makefile
doc/reference/meta-docs.sgml
src/Makefile
src/libmutter.pc
src/libmutter-wayland.pc
src/compositor/plugins/Makefile
po/Makefile.in
])
@ -408,7 +468,7 @@ fi
dnl ==========================================================================
echo "
mutter-$VERSION
mutter-wayland-$VERSION
prefix: ${prefix}
source code location: ${srcdir}
@ -418,6 +478,8 @@ mutter-$VERSION
libcanberra: ${have_libcanberra}
Introspection: ${found_introspection}
Session management: ${found_sm}
Shape extension: ${found_shape}
Xsync: ${found_xsync}
"

View File

@ -1,3 +0,0 @@
defaultcursordir = $(datadir)/mutter/cursors
dist_defaultcursor_DATA = left_ptr.png

View File

@ -79,6 +79,8 @@ IGNORE_HFILES= \
iconcache.h \
inlinepixbufs.h \
keybindings-private.h \
menu.h \
metaaccellabel.h \
meta-background-actor-private.h \
meta-background-group-private.h \
meta-module.h \
@ -138,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

View File

@ -21,6 +21,7 @@ environment.</description>
-->
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnome-shell-list" />
<download-page rdf:resource="http://download.gnome.org/sources/mutter/" />
<download-page rdf:resource="http://download.gnome.org/sources/mutter-wayland/" />
<bug-database rdf:resource="http://bugzilla.gnome.org/browse.cgi?product=mutter" />
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />

View File

@ -3,7 +3,6 @@
src/50-mutter-navigation.xml.in
src/50-mutter-system.xml.in
src/50-mutter-windows.xml.in
src/backends/meta-monitor-manager.c
src/compositor/compositor.c
src/compositor/meta-background.c
src/core/bell.c
@ -13,18 +12,21 @@ src/core/display.c
src/core/errors.c
src/core/keybindings.c
src/core/main.c
src/core/monitor.c
src/core/mutter.c
src/core/prefs.c
src/core/screen.c
src/x11/session.c
src/core/util.c
src/core/window.c
src/mutter.desktop.in
src/x11/window-props.c
src/x11/xprops.c
src/mutter-wayland.desktop.in
src/org.gnome.mutter.gschema.xml.in
src/org.gnome.mutter.wayland.gschema.xml.in
src/ui/frames.c
src/ui/menu.c
src/ui/metaaccellabel.c
src/ui/resizepopup.c
src/ui/theme.c
src/ui/theme-parser.c
src/x11/session.c
src/x11/window-props.c
src/x11/xprops.c

View File

@ -1,2 +1,2 @@
src/metacity.schemas.in
src/mutter-wayland.desktop.in

733
po/ar.po

File diff suppressed because it is too large Load Diff

2973
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

735
po/cs.po

File diff suppressed because it is too large Load Diff

771
po/da.po

File diff suppressed because it is too large Load Diff

3597
po/el.po

File diff suppressed because it is too large Load Diff

1737
po/es.po

File diff suppressed because it is too large Load Diff

787
po/eu.po

File diff suppressed because it is too large Load Diff

756
po/fr.po

File diff suppressed because it is too large Load Diff

3214
po/ga.po

File diff suppressed because it is too large Load Diff

1234
po/gl.po

File diff suppressed because it is too large Load Diff

1583
po/he.po

File diff suppressed because it is too large Load Diff

790
po/hu.po

File diff suppressed because it is too large Load Diff

951
po/id.po

File diff suppressed because it is too large Load Diff

737
po/it.po

File diff suppressed because it is too large Load Diff

2012
po/kn.po

File diff suppressed because it is too large Load Diff

531
po/ko.po

File diff suppressed because it is too large Load Diff

730
po/lt.po

File diff suppressed because it is too large Load Diff

528
po/lv.po

File diff suppressed because it is too large Load Diff

716
po/nb.po

File diff suppressed because it is too large Load Diff

1194
po/nl.po

File diff suppressed because it is too large Load Diff

524
po/pa.po

File diff suppressed because it is too large Load Diff

725
po/pl.po

File diff suppressed because it is too large Load Diff

797
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

992
po/ru.po

File diff suppressed because it is too large Load Diff

417
po/sk.po
View File

@ -13,9 +13,9 @@ msgstr ""
"Project-Id-Version: mutter\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-08-21 17:41+0000\n"
"PO-Revision-Date: 2013-08-02 14:46+0200\n"
"Last-Translator: Ján Kyselica <kyselica.jan@gmail.com>\n"
"POT-Creation-Date: 2013-05-24 21:44+0000\n"
"PO-Revision-Date: 2013-05-18 16:53+0100\n"
"Last-Translator: Jan Kyselica <kyselica.jan@gmail.com>\n"
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
@ -87,8 +87,9 @@ msgstr "Prepnúť okná aplikácie"
# PK: zisti co to robi
# description
#: ../src/50-mutter-navigation.xml.in.h:13
#, fuzzy
msgid "Switch system controls"
msgstr "Prepnúť medzi ovládacími prvkami systému"
msgstr "Prepnúť medzi systémovými ovládacími prvkami"
# description
#: ../src/50-mutter-navigation.xml.in.h:14
@ -103,8 +104,9 @@ msgstr "Prepnúť okná aplikácie priamo"
# MČ: podobne ako vyššie: „cycle-panels“
# description
#: ../src/50-mutter-navigation.xml.in.h:16
#, fuzzy
msgid "Switch system controls directly"
msgstr "Prepnúť medzi ovládacími prvkami systému priamo"
msgstr "Prepnúť medzi systémovými ovládacími prvkami priamo"
# description
#: ../src/50-mutter-navigation.xml.in.h:17
@ -265,13 +267,13 @@ msgstr "Zobraziť rozdelenie napravo"
# PK: je %i cislo obrazovky? ak ano tak "č. %i"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: ../src/compositor/compositor.c:596
#, c-format
#: ../src/compositor/compositor.c:571
#, fuzzy, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
"\"."
msgstr ""
"Pre obrazovku č. %i na displeji „%s“ je spustený už iný správca rozloženia."
"Pre obrazovku %i na displeji „%s“ je spustený už iný správca rozloženia."
#: ../src/compositor/meta-background.c:1076
msgid "background texture could not be created from file"
@ -311,18 +313,18 @@ msgstr "_Počkať"
msgid "_Force Quit"
msgstr "_Vynútiť ukončenie"
#: ../src/core/display.c:421
#: ../src/core/display.c:401
#, c-format
msgid "Missing %s extension required for compositing"
msgstr "Rozšírenie %s, potrebné pre kompozitné prostredie, chýba"
# X window system preloz, napr. system na spravu okien X
#: ../src/core/display.c:513
#: ../src/core/display.c:493
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "Zlyhalo otvorenie displeja systému na správu okien X „%s“\n"
#: ../src/core/keybindings.c:1136
#: ../src/core/keybindings.c:970
#, c-format
msgid ""
"Some other program is already using the key %s with modifiers %x as a "
@ -330,7 +332,7 @@ msgid ""
msgstr ""
"Iný program už používa kláves %s s modifikátormi %x ako klávesovú skratku\n"
#: ../src/core/keybindings.c:1333
#: ../src/core/keybindings.c:1151
#, c-format
msgid "\"%s\" is not a valid accelerator\n"
msgstr "„%s“ nie je platný akcelerátor\n"
@ -376,20 +378,6 @@ msgid ""
msgstr ""
"Nepodarilo sa nájsť tému! Overte, že %s existuje a obsahuje obvyklé témy.\n"
#: ../src/core/monitor.c:702
msgid "Built-in display"
msgstr "Vstavaný displej"
#. TRANSLATORS: this is a monitor name (in case we don't know
#. the vendor), it's Unknown followed by a size in inches,
#. like 'Unknown 15"'
#.
#: ../src/core/monitor.c:730
#, c-format
#| msgid "Unknown element %s"
msgid "Unknown %s"
msgstr "Neznámy %s"
#: ../src/core/mutter.c:40
#, c-format
msgid ""
@ -415,7 +403,7 @@ msgstr "Zobrazí verziu"
msgid "Mutter plugin to use"
msgstr "Použije zásuvný modul Mutter"
#: ../src/core/prefs.c:1202
#: ../src/core/prefs.c:1193
msgid ""
"Workarounds for broken applications disabled. Some applications may not "
"behave properly.\n"
@ -423,12 +411,12 @@ msgstr ""
"Náhradné riešenia pre chybné aplikácie nie sú povolené. Niektoré aplikácie "
"sa nemusia správať správne.\n"
#: ../src/core/prefs.c:1277
#: ../src/core/prefs.c:1268
#, c-format
msgid "Could not parse font description \"%s\" from GSettings key %s\n"
msgstr "Nepodarilo sa spracovať popis písma „%s“ z kľúča GSettings %s\n"
#: ../src/core/prefs.c:1343
#: ../src/core/prefs.c:1334
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for mouse button "
@ -437,7 +425,7 @@ msgstr ""
"V konfiguračnej databáze sa našlo „%s“, čo nie je platná hodnota pre "
"modifikátor tlačidla myši\n"
#: ../src/core/prefs.c:1909
#: ../src/core/prefs.c:1881
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for keybinding "
@ -446,17 +434,17 @@ msgstr ""
"V konfiguračnej databáze sa našlo „%s“, čo nie je platná hodnota pre "
"klávesovú skratku „%s“\n"
#: ../src/core/prefs.c:1999
#: ../src/core/prefs.c:1945
#, c-format
msgid "Workspace %d"
msgstr "Pracovný priestor č. %d"
#: ../src/core/screen.c:537
#: ../src/core/screen.c:691
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "Obrazovka č. %d na displeji „%s“ nie je platná\n"
#: ../src/core/screen.c:553
#: ../src/core/screen.c:707
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@ -465,7 +453,7 @@ msgstr ""
"Obrazovka č. %d na displeji „%s“ už má správcu okien. Skúste použiť prepínač "
"--replace, aby sa aktuálny správca nahradil.\n"
#: ../src/core/screen.c:580
#: ../src/core/screen.c:734
#, c-format
msgid ""
"Could not acquire window manager selection on screen %d display \"%s\"\n"
@ -473,12 +461,12 @@ msgstr ""
"Nepodarilo sa získať výber správcu okien pre obrazovku č. %d na displeji "
"„%s“\n"
#: ../src/core/screen.c:658
#: ../src/core/screen.c:812
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr "Obrazovka č. %d na displeji „%s“ už má správcu okien\n"
#: ../src/core/screen.c:850
#: ../src/core/screen.c:998
#, c-format
msgid "Could not release screen %d on display \"%s\"\n"
msgstr "Nepodarilo sa uvoľniť obrazovku č. %d na displeji „%s“\n"
@ -554,7 +542,8 @@ msgstr "Zlyhalo otvorenie súboru so záznamom pomocou fdopen() %s: %s\n"
msgid "Opened log file %s\n"
msgstr "Otvorený súbor so záznamom %s\n"
#: ../src/core/util.c:119
#: ../src/core/util.c:119 ../src/tools/mutter-message.c:149
#, c-format
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Mutter bol skompilovaný bez výpisu podrobností pri behu\n"
@ -562,20 +551,20 @@ msgstr "Mutter bol skompilovaný bez výpisu podrobností pri behu\n"
msgid "Window manager: "
msgstr "Správca okien: "
#: ../src/core/util.c:414
#: ../src/core/util.c:412
msgid "Bug in window manager: "
msgstr "Chyba v správcovi okien: "
#: ../src/core/util.c:445
#: ../src/core/util.c:443
msgid "Window manager warning: "
msgstr "Varovanie správcu okien: "
#: ../src/core/util.c:473
#: ../src/core/util.c:471
msgid "Window manager error: "
msgstr "Chyba správcu okien: "
#. first time through
#: ../src/core/window.c:7533
#: ../src/core/window.c:7505
#, c-format
msgid ""
"Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER "
@ -591,7 +580,7 @@ msgstr ""
#. * MWM but not WM_NORMAL_HINTS are basically broken. We complain
#. * about these apps but make them work.
#.
#: ../src/core/window.c:8257
#: ../src/core/window.c:8229
#, c-format
msgid ""
"Window %s sets an MWM hint indicating it isn't resizable, but sets min size "
@ -601,7 +590,7 @@ msgstr ""
"nastavuje minimálnu veľkosť %d x %d a maximálnu veľkosť %d x %d. To nedáva "
"zmysel.\n"
#: ../src/core/window-props.c:347
#: ../src/core/window-props.c:318
#, c-format
msgid "Application set a bogus _NET_WM_PID %lu\n"
msgstr "Aplikácia nastavila neplatné _NET_WM_PID %lu\n"
@ -609,18 +598,18 @@ msgstr "Aplikácia nastavila neplatné _NET_WM_PID %lu\n"
# PK: co je toto?
# JK: nedokazem zistit
# PM: vyžiadaj komentár od vývojárov, pomožeme aj ostatným prekladateľom
#: ../src/core/window-props.c:463
#: ../src/core/window-props.c:434
#, fuzzy, c-format
msgid "%s (on %s)"
msgstr "%s (na %s)"
#: ../src/core/window-props.c:1546
#: ../src/core/window-props.c:1517
#, c-format
msgid "Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n"
msgstr "Neplatné WM_TRANSIENT_FOR okno 0x%lx nastavené pre %s.\n"
# MČ: zacykliť sa, alebo vytvoriť slučku.
#: ../src/core/window-props.c:1557
#: ../src/core/window-props.c:1528
#, c-format
msgid "WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n"
msgstr "WM_TRANSIENT_FOR okno 0x%lx pre %s môže vytvoriť slučku.\n"
@ -708,9 +697,9 @@ msgid ""
"vertically and resizes them horizontally to cover half of the available "
"area. Dropping windows on the top screen edge maximizes them completely."
msgstr ""
"Ak je povolené, upustenie okien pri zvislých okrajoch obrazovky ich zvislo "
"maximalizuje a vodorovná veľkosť sa zmení na polovicu dostupnej plochy. "
"Upustenie okien pri vrchnom okraji obrazovky ich maximalizuje úplne."
"Ak je povolené, upustenie okien pri zvislých okrajoch obrazovky ich "
"zvislo maximalizuje a vodorovná veľkosť sa zmení na polovicu dostupnej "
"plochy. Upustenie okien pri vrchnom okraji obrazovky ich maximalizuje úplne."
# summary
#: ../src/org.gnome.mutter.gschema.xml.in.h:7
@ -746,8 +735,9 @@ msgstr ""
# PM: ja by som dal Bez vyvovlávania tabulátorom
# summary
#: ../src/org.gnome.mutter.gschema.xml.in.h:11
#, fuzzy
msgid "No tab popup"
msgstr "Bez vyvolávania tabulátorom"
msgstr "Nepoužívať prekryvnú ponuku tabulátora"
# MČ: Neviem, čo to presne má robiť, ale popis som pochopil inak. „…či sa má používať rozbaľovacia ponuka a zvýraznenie rámikom sa má vypnúť…“
# description
@ -816,104 +806,109 @@ msgstr "Vybrať okno z rozbaľovacej ponuky tabulátoru"
msgid "Cancel tab popup"
msgstr "Zrušit rozbaľovaciu ponuku tabulátoru"
#: ../src/tools/mutter-message.c:123
#, c-format
msgid "Usage: %s\n"
msgstr "Použitie: %s\n"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:67
#: ../src/ui/menu.c:69
msgid "Mi_nimize"
msgstr "Mi_nimalizovať"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:69
#: ../src/ui/menu.c:71
msgid "Ma_ximize"
msgstr "Ma_ximalizovať"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:71
#: ../src/ui/menu.c:73
msgid "Unma_ximize"
msgstr "Zrušiť ma_ximalizáciu"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:73
#: ../src/ui/menu.c:75
msgid "Roll _Up"
msgstr "_Zabaliť"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:75
#: ../src/ui/menu.c:77
msgid "_Unroll"
msgstr "_Rozbaliť"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:77
#: ../src/ui/menu.c:79
msgid "_Move"
msgstr "Pre_miestniť"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:79
#: ../src/ui/menu.c:81
msgid "_Resize"
msgstr "Zmeniť veľko_sť"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:81
#: ../src/ui/menu.c:83
msgid "Move Titlebar On_screen"
msgstr "Presunúť titulok na _obrazovku"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:84 ../src/ui/menu.c:86
#: ../src/ui/menu.c:86 ../src/ui/menu.c:88
msgid "Always on _Top"
msgstr "Vždy na_vrchu"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:88
#: ../src/ui/menu.c:90
msgid "_Always on Visible Workspace"
msgstr "Vž_dy na viditeľnom pracovnom priestore"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:90
#: ../src/ui/menu.c:92
msgid "_Only on This Workspace"
msgstr "_Len na tomto pracovnom priestore"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:92
#: ../src/ui/menu.c:94
msgid "Move to Workspace _Left"
msgstr "Presunúť na pracovný priestor vľav_o"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:94
#: ../src/ui/menu.c:96
msgid "Move to Workspace R_ight"
msgstr "Presunúť na pracovný priestor v_pravo"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:96
#: ../src/ui/menu.c:98
msgid "Move to Workspace _Up"
msgstr "Presunúť na pracovný priestor _hore"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:98
#: ../src/ui/menu.c:100
msgid "Move to Workspace _Down"
msgstr "Presunúť na pracovný priestor _dole"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:102
#: ../src/ui/menu.c:104
msgid "_Close"
msgstr "_Zavrieť"
#: ../src/ui/menu.c:202
#: ../src/ui/menu.c:204
#, c-format
msgid "Workspace %d%n"
msgstr "Pracovná priestor %d%n"
#: ../src/ui/menu.c:212
#: ../src/ui/menu.c:214
#, c-format
msgid "Workspace 1_0"
msgstr "Pracovný priestor 1_0"
#: ../src/ui/menu.c:214
#: ../src/ui/menu.c:216
#, c-format
msgid "Workspace %s%d"
msgstr "Pracovný priestor %s%d"
#: ../src/ui/menu.c:384
#: ../src/ui/menu.c:397
msgid "Move to Another _Workspace"
msgstr "P_resunúť na iný pracovný priestor"
@ -1071,21 +1066,21 @@ msgstr ""
# MČ: Preformuloval by som koniec: „platné sú len znaky A-Za-z0-9-_“
# PK: color_name je asi nejaky atribut, to sa nepreklada, ked tak do zatvorky
#: ../src/ui/theme.c:1219
#, c-format
#, fuzzy, c-format
msgid ""
"Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-"
"_ are valid"
msgstr ""
"V parametri color_name (názov farby) pre gtk:custom je neplatný znak „%c“, platné sú len "
"V parametri názov_farby pre gtk:custom je neplatný znak „%c“, platné sú len "
"znaky A-Za-z0-9-_"
#: ../src/ui/theme.c:1233
#, c-format
#, fuzzy, c-format
msgid ""
"Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not "
"fit the format"
msgstr ""
"Formát Gtk:custom je „gtk:custom(color_name,fallback)“, „%s“ tomu "
"Formát Gtk:custom je „gtk:custom(názov_farby,fallback)“, „%s“ tomu "
"nezodpovedá"
#: ../src/ui/theme.c:1278
@ -1271,20 +1266,20 @@ msgid ""
"Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
msgstr "Chýbajúce <frame state=„%s“ resize=„%s“ focus=„%s“ style=„whatever“/>"
#: ../src/ui/theme.c:5082
#: ../src/ui/theme.c:5084
#, c-format
msgid "Failed to load theme \"%s\": %s\n"
msgstr "Zlyhalo načítanie témy „%s“: %s\n"
# PK: prvok?
# JK: XML značka (XML tag)
#: ../src/ui/theme.c:5218 ../src/ui/theme.c:5225 ../src/ui/theme.c:5232
#: ../src/ui/theme.c:5239 ../src/ui/theme.c:5246
#: ../src/ui/theme.c:5220 ../src/ui/theme.c:5227 ../src/ui/theme.c:5234
#: ../src/ui/theme.c:5241 ../src/ui/theme.c:5248
#, c-format
msgid "No <%s> set for theme \"%s\""
msgstr "Pre tému „%s“ nie je nastavená <%s>"
#: ../src/ui/theme.c:5254
#: ../src/ui/theme.c:5256
#, c-format
msgid ""
"No frame style set for window type \"%s\" in theme \"%s\", add a <window "
@ -1293,13 +1288,13 @@ msgstr ""
"Pre typ okna „%s“ nie je sada štýlov v téme „%s“, pridajte prvok <window "
"type=„%s“ style_set=„whatever“/>"
#: ../src/ui/theme.c:5661 ../src/ui/theme.c:5723 ../src/ui/theme.c:5786
#: ../src/ui/theme.c:5663 ../src/ui/theme.c:5725 ../src/ui/theme.c:5788
#, c-format
msgid ""
"User-defined constants must begin with a capital letter; \"%s\" does not"
msgstr "Používateľské konštanty musia začínať veľkým písmenom, „%s“ nezačína"
#: ../src/ui/theme.c:5669 ../src/ui/theme.c:5731 ../src/ui/theme.c:5794
#: ../src/ui/theme.c:5671 ../src/ui/theme.c:5733 ../src/ui/theme.c:5796
#, c-format
msgid "Constant \"%s\" has already been defined"
msgstr "Konštanta „%s“ už je definovaná"
@ -1402,7 +1397,7 @@ msgstr "<%s> musí uvádzať buď geometriu alebo rodiča, ktorý má geometriu"
msgid "You must specify a background for an alpha value to be meaningful"
msgstr "Ak má byť hodnota alpha zmysluplná, tak musíte vybrať nejaké pozadie"
#  PM: asi atribút type
# PM: asi atribút type
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=698123
#: ../src/ui/theme-parser.c:1264
#, fuzzy, c-format
@ -1564,7 +1559,6 @@ msgid "\"%s\" is not a valid value for resize attribute"
msgstr "„%s“ nie je platná hodnota pre atribút zmeny veľkosti"
# PK: shaded states? to zatvorky daj popis co je resize
# PM: skôr "pre stavy maximized (maximalizovaný)/shaded (zatienený)"
#: ../src/ui/theme-parser.c:3147
#, fuzzy, c-format
msgid ""
@ -1706,172 +1700,221 @@ msgstr "<%s> uvedený dvakrát pre túto tému"
msgid "Failed to find a valid file for theme %s\n"
msgstr "Zlyhalo nájdenie platného súboru pre tému%s\n"
#~ msgid "Usage: %s\n"
#~ msgstr "Použitie: %s\n"
#: ../src/ui/theme-viewer.c:99
msgid "_Windows"
msgstr "_Okná"
#~ msgid "_Windows"
#~ msgstr "_Okná"
#: ../src/ui/theme-viewer.c:100
msgid "_Dialog"
msgstr "_Dialógové okno"
#~ msgid "_Dialog"
#~ msgstr "_Dialógové okno"
#: ../src/ui/theme-viewer.c:101
msgid "_Modal dialog"
msgstr "_Modálne dialógové okno"
#~ msgid "_Modal dialog"
#~ msgstr "_Modálne dialógové okno"
#: ../src/ui/theme-viewer.c:102
msgid "_Utility"
msgstr "_Nástroje"
#~ msgid "_Utility"
#~ msgstr "_Nástroje"
#~ msgid "_Splashscreen"
#~ msgstr "Ú_vodná obrazovka"
#: ../src/ui/theme-viewer.c:103
msgid "_Splashscreen"
msgstr "Ú_vodná obrazovka"
# MČ: nie som si istý prekladom „dok“, nemal by to byť „panel“?
#~ msgid "_Top dock"
#~ msgstr "_Horný panel"
#: ../src/ui/theme-viewer.c:104
msgid "_Top dock"
msgstr "_Horný panel"
#~ msgid "_Bottom dock"
#~ msgstr "_Spodný panel"
#: ../src/ui/theme-viewer.c:105
msgid "_Bottom dock"
msgstr "_Spodný panel"
#~ msgid "_Left dock"
#~ msgstr "Ľ_avý panel"
#: ../src/ui/theme-viewer.c:106
msgid "_Left dock"
msgstr "Ľ_avý panel"
#~ msgid "_Right dock"
#~ msgstr "_Pravý panel"
#: ../src/ui/theme-viewer.c:107
msgid "_Right dock"
msgstr "_Pravý panel"
#~ msgid "_All docks"
#~ msgstr "_Všetky panely"
#: ../src/ui/theme-viewer.c:108
msgid "_All docks"
msgstr "_Všetky panely"
#~ msgid "Des_ktop"
#~ msgstr "P_racovná plocha"
#: ../src/ui/theme-viewer.c:109
msgid "Des_ktop"
msgstr "P_racovná plocha"
# tooltip
#~ msgid "Open another one of these windows"
#~ msgstr "Otvorí ďalšie z týchto okien"
#: ../src/ui/theme-viewer.c:115
msgid "Open another one of these windows"
msgstr "Otvorí ďalšie z týchto okien"
# PK: prekladat to v uvodzovkach? nahlas bug
# tooltip
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=698123
#: ../src/ui/theme-viewer.c:117
#, fuzzy
#~ msgid "This is a demo button with an 'open' icon"
#~ msgstr "Toto je ukážkové tlačidlo s ikonou „open“"
msgid "This is a demo button with an 'open' icon"
msgstr "Toto je ukážkové tlačidlo s ikonou „open“"
# tooltip
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=698123
#: ../src/ui/theme-viewer.c:119
#, fuzzy
#~ msgid "This is a demo button with a 'quit' icon"
#~ msgstr "Toto je ukážkové tlačidlo s ikonou „quit“"
msgid "This is a demo button with a 'quit' icon"
msgstr "Toto je ukážkové tlačidlo s ikonou „quit“"
# label
#~ msgid "This is a sample message in a sample dialog"
#~ msgstr "Toto je ukážková správa v ukážkovom dialógovom okne"
#: ../src/ui/theme-viewer.c:248
msgid "This is a sample message in a sample dialog"
msgstr "Toto je ukážková správa v ukážkovom dialógovom okne"
# PK: falosna
#~ msgid "Fake menu item %d\n"
#~ msgstr "Falošná položka ponuky č. %d\n"
#: ../src/ui/theme-viewer.c:328
#, c-format
msgid "Fake menu item %d\n"
msgstr "Falošná položka ponuky č. %d\n"
#~ msgid "Border-only window"
#~ msgstr "Okno len s okrajom"
#: ../src/ui/theme-viewer.c:363
msgid "Border-only window"
msgstr "Okno len s okrajom"
#~ msgid "Bar"
#~ msgstr "Lišta"
#: ../src/ui/theme-viewer.c:365
msgid "Bar"
msgstr "Lišta"
#~ msgid "Normal Application Window"
#~ msgstr "Normálne aplikačné okno"
#: ../src/ui/theme-viewer.c:382
msgid "Normal Application Window"
msgstr "Normálne aplikačné okno"
#~ msgid "Dialog Box"
#~ msgstr "Dialógové okno"
#: ../src/ui/theme-viewer.c:386
msgid "Dialog Box"
msgstr "Dialógové okno"
#~ msgid "Modal Dialog Box"
#~ msgstr "Modálne dialógové okno"
#: ../src/ui/theme-viewer.c:390
msgid "Modal Dialog Box"
msgstr "Modálne dialógové okno"
#~ msgid "Utility Palette"
#~ msgstr "Paleta nástrojov"
#: ../src/ui/theme-viewer.c:394
msgid "Utility Palette"
msgstr "Paleta nástrojov"
#~ msgid "Torn-off Menu"
#~ msgstr "Vypnúť ponuku"
#: ../src/ui/theme-viewer.c:398
msgid "Torn-off Menu"
msgstr "Vypnúť ponuku"
#~ msgid "Border"
#~ msgstr "Okraj"
#: ../src/ui/theme-viewer.c:402
msgid "Border"
msgstr "Okraj"
#~ msgid "Attached Modal Dialog"
#~ msgstr "Pričlenené modálne okno"
#: ../src/ui/theme-viewer.c:406
msgid "Attached Modal Dialog"
msgstr "Pričlenené modálne okno"
#~ msgid "Button layout test %d"
#~ msgstr "Test rozloženia tlačidiel č. %d"
#: ../src/ui/theme-viewer.c:737
#, c-format
msgid "Button layout test %d"
msgstr "Test rozloženia tlačidiel č. %d"
# PK: plural forms
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=697987
#, fuzzy
#~ msgid "%g milliseconds to draw one window frame"
#~ msgstr "%g milisekúnd pre vykreslenie jedného rámca okna"
#: ../src/ui/theme-viewer.c:766
#, fuzzy, c-format
msgid "%g milliseconds to draw one window frame"
msgstr "%g milisekúnd pre vykreslenie jedného rámca okna"
#~ msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
#~ msgstr "Použitie: metacity-theme-viewer [NÁZOVTÉMY]\n"
#: ../src/ui/theme-viewer.c:811
#, c-format
msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
msgstr "Použitie: metacity-theme-viewer [NÁZOVTÉMY]\n"
#~ msgid "Error loading theme: %s\n"
#~ msgstr "Chyba pri načítavaní témy: %s\n"
#: ../src/ui/theme-viewer.c:818
#, c-format
msgid "Error loading theme: %s\n"
msgstr "Chyba pri načítavaní témy: %s\n"
# PK: plural forms
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=697987
#, fuzzy
#~ msgid "Loaded theme \"%s\" in %g seconds\n"
#~ msgstr "Téma „%s“ načítaná za %g send\n"
#: ../src/ui/theme-viewer.c:824
#, fuzzy, c-format
msgid "Loaded theme \"%s\" in %g seconds\n"
msgstr "Téma „%s“ načítaná za %g sekúnd\n"
# PK: inde titulku, aky je rozdiel
#~ msgid "Normal Title Font"
#~ msgstr "Obyčajné písmo titulku"
#: ../src/ui/theme-viewer.c:869
msgid "Normal Title Font"
msgstr "Obyčajné písmo titulku"
#~ msgid "Small Title Font"
#~ msgstr "Malé písmo titulku"
#: ../src/ui/theme-viewer.c:875
msgid "Small Title Font"
msgstr "Malé písmo titulku"
#~ msgid "Large Title Font"
#~ msgstr "Veľké písmo titulku"
#: ../src/ui/theme-viewer.c:881
msgid "Large Title Font"
msgstr "Veľké písmo titulku"
#~ msgid "Button Layouts"
#~ msgstr "Rozloženia tlačidiel"
#: ../src/ui/theme-viewer.c:886
msgid "Button Layouts"
msgstr "Rozloženia tlačidiel"
#~ msgid "Benchmark"
#~ msgstr "Test rýchlosti"
#: ../src/ui/theme-viewer.c:891
msgid "Benchmark"
msgstr "Test rýchlosti"
#~ msgid "Window Title Goes Here"
#~ msgstr "Sem príde názov okna"
#: ../src/ui/theme-viewer.c:947
msgid "Window Title Goes Here"
msgstr "Sem príde názov okna"
# PK: plural forms
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=697987
#, fuzzy
#~ msgid ""
#~ "Drew %d frames in %g client-side seconds (%g milliseconds per frame) and "
#~ "%g seconds wall clock time including X server resources (%g milliseconds "
#~ "per frame)\n"
#~ msgstr ""
#~ "Vykreslených %d rámcov za %g sekúnd na strane klienta (%g milisekúnd na "
#~ "rámec) a %g sekúnd celkového času vrátane zdrojov servera X (%g "
#~ "milisekúnd na rámec)\n"
#: ../src/ui/theme-viewer.c:1053
#, fuzzy, c-format
msgid ""
"Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g "
"seconds wall clock time including X server resources (%g milliseconds per "
"frame)\n"
msgstr ""
"Vykreslených %d rámcov za %g sekúnd na strane klienta (%g milisekúnd na "
"rámec) a %g sekúnd celkového času vrátane zdrojov servera X (%g milisekúnd "
"na rámec)\n"
#~ msgid "position expression test returned TRUE but set error"
#~ msgstr "test výrazu polohy vrátil TRUE, ale nastavil chybu"
#: ../src/ui/theme-viewer.c:1273
msgid "position expression test returned TRUE but set error"
msgstr "test výrazu polohy vrátil TRUE, ale nastavil chybu"
#~ msgid "position expression test returned FALSE but didn't set error"
#~ msgstr "test výrazu polohy vrátil FALSE, ale nenastavil chybu"
#: ../src/ui/theme-viewer.c:1275
msgid "position expression test returned FALSE but didn't set error"
msgstr "test výrazu polohy vrátil FALSE, ale nenastavil chybu"
#~ msgid "Error was expected but none given"
#~ msgstr "Bola očakávaná chyba, ale žiadna nenastala"
#: ../src/ui/theme-viewer.c:1279
msgid "Error was expected but none given"
msgstr "Bola očakávaná chyba, ale žiadna nenastala"
#~ msgid "Error %d was expected but %d given"
#~ msgstr "Bola očakávaná chyba %d, ale nastala %d"
#: ../src/ui/theme-viewer.c:1281
#, c-format
msgid "Error %d was expected but %d given"
msgstr "Bola očakávaná chyba %d, ale nastala %d"
#~ msgid "Error not expected but one was returned: %s"
#~ msgstr "Chyba nebola očakávaná, ale bola vrátená: %s"
#: ../src/ui/theme-viewer.c:1287
#, c-format
msgid "Error not expected but one was returned: %s"
msgstr "Chyba nebola očakávaná, ale bola vrátená: %s"
#~ msgid "x value was %d, %d was expected"
#~ msgstr "hodnota x bola %d, očakávaná bola %d"
#: ../src/ui/theme-viewer.c:1291
#, c-format
msgid "x value was %d, %d was expected"
msgstr "hodnota x bola %d, očakávaná bola %d"
#~ msgid "y value was %d, %d was expected"
#~ msgstr "hodnota y bola %d, očakávaná bola %d"
#: ../src/ui/theme-viewer.c:1294
#, c-format
msgid "y value was %d, %d was expected"
msgstr "hodnota y bola %d, očakávaná bola %d"
# PK: plural forms
# JK: https://bugzilla.gnome.org/show_bug.cgi?id=697987
#, fuzzy
#~ msgid ""
#~ "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
#~ msgstr ""
#~ "%d výrazov pre súradnice analyzovaných za %g sekúnd (priemer %g sekúnd)\n"
#: ../src/ui/theme-viewer.c:1359
#, fuzzy, c-format
msgid "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
msgstr ""
"%d výrazov pre súradnice analyzovaných za %g sekúnd (priemer %g sekúnd)\n"

789
po/sl.po

File diff suppressed because it is too large Load Diff

758
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1132
po/uk.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,9 +17,6 @@
<KeyListEntry name="move-to-workspace-4"
_description="Move window to workspace 4" />
<KeyListEntry name="move-to-workspace-last"
_description="Move window to last workspace" />
<KeyListEntry name="move-to-workspace-left"
_description="Move window one workspace to the left" />
@ -80,9 +77,6 @@
<KeyListEntry name="switch-to-workspace-4"
_description="Switch to workspace 4" />
<KeyListEntry name="switch-to-workspace-last"
_description="Switch to last workspace" />
<KeyListEntry name="switch-to-workspace-left"
_description="Move to workspace left" />

View File

@ -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
@ -11,6 +11,7 @@ INCLUDES= \
-DCOGL_ENABLE_EXPERIMENTAL_API \
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
$(MUTTER_CFLAGS) \
-I$(top_builddir) \
-I$(srcdir) \
-I$(srcdir)/backends \
-I$(srcdir)/core \
@ -35,30 +36,28 @@ INCLUDES= \
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_display_config_built_sources) \
$(dbus_login1_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
gtk-shell-protocol.c \
gtk-shell-server-protocol.h \
xdg-shell-protocol.c \
xdg-shell-server-protocol.h
xdg-shell-server-protocol.h \
xserver-protocol.c \
xserver-server-protocol.h
wayland_protocols = \
wayland/protocol/gtk-shell.xml \
wayland/protocol/xdg-shell.xml
wayland/protocol/xdg-shell.xml \
wayland/protocol/xserver.xml
libmutter_la_SOURCES = \
libmutter_wayland_la_SOURCES = \
backends/meta-backend.c \
backends/meta-backend.h \
backends/meta-backend-private.h \
backends/meta-cursor.c \
backends/meta-cursor.h \
backends/meta-cursor-private.h \
backends/meta-cursor-tracker.c \
backends/meta-cursor-tracker-private.h \
backends/meta-cursor-renderer.c \
backends/meta-cursor-renderer.h \
backends/meta-display-config-shared.h \
backends/meta-idle-monitor.c \
backends/meta-idle-monitor-private.h \
backends/meta-idle-monitor-dbus.c \
@ -71,28 +70,22 @@ libmutter_la_SOURCES = \
backends/meta-monitor-manager-dummy.h \
backends/edid-parse.c \
backends/edid.h \
backends/native/meta-backend-native.c \
backends/native/meta-backend-native.h \
backends/native/meta-cursor-renderer-native.c \
backends/native/meta-cursor-renderer-native.h \
backends/native/meta-cursor-tracker-native.c \
backends/native/meta-cursor-tracker-native.h \
backends/native/meta-idle-monitor-native.c \
backends/native/meta-idle-monitor-native.h \
backends/native/meta-monitor-manager-kms.c \
backends/native/meta-monitor-manager-kms.h \
backends/native/meta-launcher.c \
backends/native/meta-launcher.h \
backends/native/dbus-utils.c \
backends/native/dbus-utils.h \
backends/x11/meta-backend-x11.c \
backends/x11/meta-backend-x11.h \
backends/x11/meta-cursor-renderer-x11.c \
backends/x11/meta-cursor-renderer-x11.h \
backends/native/meta-weston-launch.c \
backends/native/meta-weston-launch.h \
backends/x11/meta-cursor-tracker-x11.c \
backends/x11/meta-cursor-tracker-x11.h \
backends/x11/meta-idle-monitor-xsync.c \
backends/x11/meta-idle-monitor-xsync.h \
backends/x11/meta-monitor-manager-xrandr.c \
backends/x11/meta-monitor-manager-xrandr.h \
core/meta-accel-parse.c \
core/meta-accel-parse.h \
backends/x11/meta-xrandr-shared.h \
core/above-tab-keycode.c \
core/barrier.c \
meta/barrier.h \
core/bell.c \
@ -127,8 +120,6 @@ libmutter_la_SOURCES = \
compositor/meta-surface-actor-x11.h \
compositor/meta-surface-actor-wayland.c \
compositor/meta-surface-actor-wayland.h \
compositor/meta-stage.h \
compositor/meta-stage.c \
compositor/meta-texture-rectangle.c \
compositor/meta-texture-rectangle.h \
compositor/meta-texture-tower.c \
@ -194,6 +185,10 @@ libmutter_la_SOURCES = \
ui/ui.h \
ui/frames.c \
ui/frames.h \
ui/menu.c \
ui/menu.h \
ui/metaaccellabel.c \
ui/metaaccellabel.h \
ui/resizepopup.c \
ui/resizepopup.h \
ui/theme-parser.c \
@ -223,9 +218,8 @@ libmutter_la_SOURCES = \
wayland/meta-wayland.c \
wayland/meta-wayland.h \
wayland/meta-wayland-private.h \
wayland/meta-xwayland.c \
wayland/meta-xwayland.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 \
@ -234,20 +228,20 @@ libmutter_la_SOURCES = \
wayland/meta-wayland-pointer.h \
wayland/meta-wayland-seat.c \
wayland/meta-wayland-seat.h \
wayland/meta-wayland-stage.h \
wayland/meta-wayland-stage.c \
wayland/meta-wayland-surface.c \
wayland/meta-wayland-surface.h \
wayland/meta-wayland-types.h \
wayland/meta-wayland-versions.h \
wayland/meta-wayland-outputs.c \
wayland/meta-wayland-outputs.h \
wayland/window-wayland.c \
wayland/window-wayland.h
nodist_libmutter_la_SOURCES = \
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
libmutter_la_LDFLAGS = -no-undefined
libmutter_la_LIBADD = $(MUTTER_LIBS)
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
@ -285,16 +279,29 @@ 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
bin_PROGRAMS+=mutter-launch
mutter_launch_SOURCES = \
backends/native/weston-launch.c \
backends/native/weston-launch.h
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
install-exec-hook:
-chown root $(DESTDIR)$(bindir)/mutter-launch
-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)
@ -316,15 +323,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) $(nodist_libmutter_la_SOURCES))
$(filter %.c,$(libmutter_wayland_la_SOURCES) $(nodist_libmutter_wayland_la_SOURCES))
@META_GIR@_SCANNERFLAGS = --warn-all --warn-error
endif
@ -335,14 +342,14 @@ testasyncgetprop_SOURCES = x11/testasyncgetprop.c
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
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)
@ -363,7 +370,7 @@ convertdir = $(datadir)/GConf/gsettings
convert_DATA = mutter-schemas.convert
CLEANFILES = \
mutter.desktop \
mutter-wayland.desktop \
mutter-wm.desktop \
org.gnome.mutter.gschema.xml \
org.gnome.mutter.wayland.gschema.xml \
@ -374,7 +381,7 @@ CLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc
pkgconfig_DATA = libmutter-wayland.pc
EXTRA_DIST=$(desktopfiles_files) \
$(wmproperties_files) \
@ -386,10 +393,9 @@ EXTRA_DIST=$(desktopfiles_files) \
org.gnome.mutter.gschema.xml.in \
org.gnome.mutter.wayland.gschema.xml.in \
mutter-schemas.convert \
libmutter.pc.in \
libmutter-wayland.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.freedesktop.login1.xml \
org.gnome.Mutter.DisplayConfig.xml \
org.gnome.Mutter.IdleMonitor.xml
@ -433,15 +439,6 @@ $(dbus_idle_built_sources) : Makefile.am org.gnome.Mutter.IdleMonitor.xml
--c-generate-object-manager \
$(srcdir)/org.gnome.Mutter.IdleMonitor.xml
dbus_login1_built_sources = meta-dbus-login1.c meta-dbus-login1.h
$(dbus_login1_built_sources) : Makefile.am org.freedesktop.login1.xml
$(AM_V_GEN)gdbus-codegen \
--interface-prefix org.freedesktop.login1 \
--c-namespace Login1 \
--generate-c-code meta-dbus-login1 \
$(srcdir)/org.freedesktop.login1.xml
%-protocol.c : $(srcdir)/wayland/protocol/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml

View File

@ -179,7 +179,7 @@ decode_display_parameters (const uchar *edid, MonitorInfo *info)
else if (edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
}
else if (edid[0x15] == 0)
@ -267,7 +267,7 @@ decode_color_characteristics (const uchar *edid, MonitorInfo *info)
static int
decode_established_timings (const uchar *edid, MonitorInfo *info)
{
static const Timing established[][8] =
static const Timing established[][8] =
{
{
{ 800, 600, 60 },

View File

@ -1,9 +1,9 @@
/* edid.h
*
* Copyright 2007, 2008, Red Hat, Inc.
*
*
* This file is part of the Gnome Library.
*
*
* The Gnome Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -13,12 +13,12 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
@ -177,7 +177,7 @@ struct MonitorInfo
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
* mode, it is the first one
* (whether it has, is
* determined by the
* determined by the
* preferred_timing_includes
* bit.
*/

View File

@ -1,71 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_BACKEND_PRIVATE_H
#define META_BACKEND_PRIVATE_H
#include <glib-object.h>
#include "meta-backend.h"
#define META_TYPE_BACKEND (meta_backend_get_type ())
#define META_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKEND, MetaBackend))
#define META_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKEND, MetaBackendClass))
#define META_IS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKEND))
#define META_IS_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKEND))
#define META_BACKEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKEND, MetaBackendClass))
struct _MetaBackend
{
GObject parent;
MetaIdleMonitor *device_monitors[256];
int device_id_max;
};
struct _MetaBackendClass
{
GObjectClass parent_class;
void (* post_init) (MetaBackend *backend);
MetaIdleMonitor * (* create_idle_monitor) (MetaBackend *backend,
int device_id);
MetaMonitorManager * (* create_monitor_manager) (MetaBackend *backend);
MetaCursorRenderer * (* create_cursor_renderer) (MetaBackend *backend);
gboolean (* grab_device) (MetaBackend *backend,
int device_id,
uint32_t timestamp);
gboolean (* ungrab_device) (MetaBackend *backend,
int device_id,
uint32_t timestamp);
void (* warp_pointer) (MetaBackend *backend,
int x,
int y);
};
#endif /* META_BACKEND_PRIVATE_H */

View File

@ -25,210 +25,14 @@
#include "config.h"
#include "meta-backend.h"
#include "meta-backend-private.h"
#include <meta/main.h>
#include <gdk/gdkx.h>
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>
#include "backends/x11/meta-backend-x11.h"
#include "backends/native/meta-backend-native.h"
static MetaBackend *_backend;
MetaBackend *
meta_get_backend (void)
{
return _backend;
}
struct _MetaBackendPrivate
{
MetaMonitorManager *monitor_manager;
MetaCursorRenderer *cursor_renderer;
};
typedef struct _MetaBackendPrivate MetaBackendPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaBackend, meta_backend, G_TYPE_OBJECT);
static void
meta_backend_finalize (GObject *object)
{
MetaBackend *backend = META_BACKEND (object);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
int i;
g_clear_object (&priv->monitor_manager);
for (i = 0; i <= backend->device_id_max; i++)
{
if (backend->device_monitors[i])
g_object_unref (backend->device_monitors[i]);
}
G_OBJECT_CLASS (meta_backend_parent_class)->finalize (object);
}
static void
meta_backend_real_post_init (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->monitor_manager = META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend);
priv->cursor_renderer = META_BACKEND_GET_CLASS (backend)->create_cursor_renderer (backend);
}
static MetaCursorRenderer *
meta_backend_real_create_cursor_renderer (MetaBackend *backend)
{
return meta_cursor_renderer_new ();
}
static gboolean
meta_backend_real_grab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
/* Do nothing */
return TRUE;
}
static gboolean
meta_backend_real_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
/* Do nothing */
return TRUE;
}
static void
meta_backend_real_warp_pointer (MetaBackend *backend,
int x,
int y)
{
/* Do nothing */
}
static void
meta_backend_class_init (MetaBackendClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_backend_finalize;
klass->post_init = meta_backend_real_post_init;
klass->create_cursor_renderer = meta_backend_real_create_cursor_renderer;
klass->grab_device = meta_backend_real_grab_device;
klass->ungrab_device = meta_backend_real_ungrab_device;
klass->warp_pointer = meta_backend_real_warp_pointer;
}
static void
meta_backend_init (MetaBackend *backend)
{
_backend = backend;
}
/* FIXME -- destroy device monitors at some point */
G_GNUC_UNUSED static void
destroy_device_monitor (MetaBackend *backend,
int device_id)
{
g_clear_object (&backend->device_monitors[device_id]);
if (device_id == backend->device_id_max)
backend->device_id_max--;
}
static MetaIdleMonitor *
meta_backend_create_idle_monitor (MetaBackend *backend,
int device_id)
{
return META_BACKEND_GET_CLASS (backend)->create_idle_monitor (backend, device_id);
}
static void
meta_backend_post_init (MetaBackend *backend)
{
META_BACKEND_GET_CLASS (backend)->post_init (backend);
}
MetaIdleMonitor *
meta_backend_get_idle_monitor (MetaBackend *backend,
int device_id)
{
g_return_val_if_fail (device_id >= 0 && device_id < 256, NULL);
if (!backend->device_monitors[device_id])
{
backend->device_monitors[device_id] = meta_backend_create_idle_monitor (backend, device_id);
backend->device_id_max = MAX (backend->device_id_max, device_id);
}
return backend->device_monitors[device_id];
}
MetaMonitorManager *
meta_backend_get_monitor_manager (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->monitor_manager;
}
MetaCursorRenderer *
meta_backend_get_cursor_renderer (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->cursor_renderer;
}
gboolean
meta_backend_grab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
return META_BACKEND_GET_CLASS (backend)->grab_device (backend, device_id, timestamp);
}
gboolean
meta_backend_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
}
void
meta_backend_warp_pointer (MetaBackend *backend,
int x,
int y)
{
META_BACKEND_GET_CLASS (backend)->warp_pointer (backend, x, y);
}
static GType
get_backend_type (void)
{
#if defined(CLUTTER_WINDOWING_X11)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
return META_TYPE_BACKEND_X11;
#endif
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
return META_TYPE_BACKEND_NATIVE;
#endif
g_assert_not_reached ();
}
static void
meta_create_backend (void)
{
/* meta_backend_init() above install the backend globally so
* so meta_get_backend() works even during initialization. */
g_object_new (get_backend_type (), NULL);
}
#include "backends/native/meta-weston-launch.h"
#include <meta/util.h>
/* Mutter is responsible for pulling events off the X queue, so Clutter
* doesn't need (and shouldn't) run its normal event source which polls
@ -278,12 +82,37 @@ static GSourceFuncs event_funcs = {
event_dispatch
};
static MetaLauncher *launcher;
void
meta_clutter_init (void)
{
GSource *source;
meta_create_backend ();
/* When running as an X11 compositor, we install our own event filter and
* pass events to Clutter explicitly, so we need to prevent Clutter from
* handling our events.
*
* However, when running as a Wayland compostior under X11 nested, Clutter
* Clutter needs to see events related to its own window. We need to
* eventually replace this with a proper frontend / backend split: Clutter
* under nested is connecting to the "host X server" to get its events it
* needs to put up a window, and GTK+ is connecting to the "inner X server".
* The two would the same in the X11 compositor case, but not when running
* XWayland as a Wayland compositor.
*/
if (!meta_is_wayland_compositor ())
{
clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
clutter_x11_disable_event_retrieval ();
}
/* If we're running on bare metal, we're a display server,
* so start talking to weston-launch. */
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
launcher = meta_launcher_new ();
#endif
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Unable to initialize Clutter.\n");
@ -291,6 +120,38 @@ meta_clutter_init (void)
source = g_source_new (&event_funcs, sizeof (GSource));
g_source_attach (source, NULL);
g_source_unref (source);
meta_backend_post_init (_backend);
}
gboolean
meta_activate_vt (int vt, GError **error)
{
if (launcher)
return meta_launcher_activate_vt (launcher, vt, error);
else
{
g_debug ("Ignoring VT switch keybinding, not running as display server");
return TRUE;
}
}
/**
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* Wayland compositor, this tells logind to switch over to
* the new session.
*/
gboolean
meta_activate_session (void)
{
GError *error = NULL;
if (!meta_launcher_activate_vt (launcher, -1, &error))
{
g_warning ("Could not activate session: %s\n", error->message);
g_error_free (error);
return FALSE;
}
return TRUE;
}

View File

@ -27,33 +27,8 @@
#include <glib-object.h>
#include <meta/meta-idle-monitor.h>
#include "meta-monitor-manager.h"
#include "meta-cursor-renderer.h"
typedef struct _MetaBackend MetaBackend;
typedef struct _MetaBackendClass MetaBackendClass;
GType meta_backend_get_type (void);
MetaBackend * meta_get_backend (void);
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
int device_id);
MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend);
MetaCursorRenderer * meta_backend_get_cursor_renderer (MetaBackend *backend);
gboolean meta_backend_grab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp);
gboolean meta_backend_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp);
void meta_backend_warp_pointer (MetaBackend *backend,
int x,
int y);
void meta_clutter_init (void);
gboolean meta_activate_vt (int vt, GError **error);
#endif /* META_BACKEND_H */

View File

@ -27,6 +27,11 @@
#include <cogl/cogl.h>
#include <gbm.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
#include <wayland-server.h>
typedef struct {
CoglTexture2D *texture;
struct gbm_bo *bo;
@ -36,7 +41,6 @@ typedef struct {
struct _MetaCursorReference {
int ref_count;
MetaCursor cursor;
MetaCursorImage image;
};
@ -48,4 +52,26 @@ struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
int *hot_x,
int *hot_y);
void meta_cursor_reference_load_gbm_buffer (MetaCursorReference *cursor,
struct gbm_device *gbm,
uint8_t *pixels,
int width,
int height,
int rowstride,
uint32_t gbm_format);
void meta_cursor_reference_import_gbm_buffer (MetaCursorReference *cursor,
struct gbm_device *gbm,
struct wl_resource *buffer,
int width,
int height);
MetaCursorReference *meta_cursor_reference_from_xfixes_cursor_image (XFixesCursorImage *cursor_image);
MetaCursorReference *meta_cursor_reference_from_xcursor_image (XcursorImage *xc_image);
MetaCursorReference *meta_cursor_reference_from_buffer (struct wl_resource *buffer,
int hot_x,
int hot_y);
#endif /* META_CURSOR_PRIVATE_H */

View File

@ -1,172 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-cursor-renderer.h"
#include "meta-cursor-private.h"
#include <cogl/cogl.h>
#include <cogl/cogl-wayland-server.h>
#include <clutter/clutter.h>
#include "meta-stage.h"
#include "wayland/meta-wayland-private.h"
struct _MetaCursorRendererPrivate
{
int current_x, current_y;
MetaRectangle current_rect;
MetaCursorReference *displayed_cursor;
gboolean handled_by_backend;
};
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
static void
queue_redraw (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
ClutterActor *stage = compositor->stage;
/* During early initialization, we can have no stage */
if (!stage)
return;
if (priv->handled_by_backend)
meta_stage_set_cursor (META_STAGE (stage), NULL, &priv->current_rect);
else
meta_stage_set_cursor (META_STAGE (stage), priv->displayed_cursor, &priv->current_rect);
}
static gboolean
meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer)
{
return FALSE;
}
static void
meta_cursor_renderer_class_init (MetaCursorRendererClass *klass)
{
klass->update_cursor = meta_cursor_renderer_real_update_cursor;
}
static void
meta_cursor_renderer_init (MetaCursorRenderer *renderer)
{
}
static void
update_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend;
gboolean should_redraw = FALSE;
if (priv->displayed_cursor)
{
CoglTexture *texture;
int hot_x, hot_y;
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, &hot_x, &hot_y);
priv->current_rect.x = priv->current_x - hot_x;
priv->current_rect.y = priv->current_y - hot_y;
priv->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
priv->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
}
else
{
priv->current_rect.x = 0;
priv->current_rect.y = 0;
priv->current_rect.width = 0;
priv->current_rect.height = 0;
}
handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer);
if (handled_by_backend != priv->handled_by_backend)
{
priv->handled_by_backend = handled_by_backend;
should_redraw = TRUE;
}
if (!handled_by_backend)
should_redraw = TRUE;
if (should_redraw)
queue_redraw (renderer);
}
MetaCursorRenderer *
meta_cursor_renderer_new (void)
{
return g_object_new (META_TYPE_CURSOR_RENDERER, NULL);
}
void
meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
MetaCursorReference *cursor)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
if (priv->displayed_cursor == cursor)
return;
priv->displayed_cursor = cursor;
update_cursor (renderer);
}
void
meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
int x, int y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->current_x = x;
priv->current_y = y;
update_cursor (renderer);
}
MetaCursorReference *
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
return priv->displayed_cursor;
}
const MetaRectangle *
meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
return &priv->current_rect;
}

View File

@ -1,70 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_CURSOR_RENDERER_H
#define META_CURSOR_RENDERER_H
#include <glib-object.h>
#include <meta/screen.h>
#include "meta-cursor.h"
#include <gbm.h>
#define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
#define META_CURSOR_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_RENDERER, MetaCursorRenderer))
#define META_CURSOR_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_RENDERER, MetaCursorRendererClass))
#define META_IS_CURSOR_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_RENDERER))
#define META_IS_CURSOR_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_RENDERER))
#define META_CURSOR_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_RENDERER, MetaCursorRendererClass))
typedef struct _MetaCursorRenderer MetaCursorRenderer;
typedef struct _MetaCursorRendererClass MetaCursorRendererClass;
struct _MetaCursorRenderer
{
GObject parent;
};
struct _MetaCursorRendererClass
{
GObjectClass parent_class;
gboolean (* update_cursor) (MetaCursorRenderer *renderer);
};
GType meta_cursor_renderer_get_type (void) G_GNUC_CONST;
MetaCursorRenderer * meta_cursor_renderer_new (void);
void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
MetaCursorReference *cursor);
void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
int x, int y);
MetaCursorReference * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
#endif /* META_CURSOR_RENDERER_H */

View File

@ -24,21 +24,36 @@
#include <meta/meta-cursor-tracker.h>
#include <wayland-server.h>
#include <gbm.h>
#include "meta-cursor.h"
#include "meta-cursor-renderer.h"
struct _MetaCursorTracker {
GObject parent_instance;
MetaScreen *screen;
MetaCursorRenderer *renderer;
gboolean is_showing;
/* The cursor tracker stores the cursor for the current grab
* operation, the cursor for the window with pointer focus, and
* the cursor for the root window, which contains either the
* default arrow cursor or the 'busy' hourglass if we're launching
* an app.
*
* We choose the first one available -- if there's a grab cursor,
* we choose that cursor, if there's window cursor, we choose that,
* otherwise we choose the root cursor.
*
* The displayed_cursor contains the chosen cursor.
*/
MetaCursorReference *displayed_cursor;
/* This is the cursor that would be displayed if we hadn't been
* asked to hide it. i.e. it's the same as displayed_cursor unless
* is_showing is false.
*/
MetaCursorReference *current_cursor;
MetaCursorReference *grab_cursor;
/* Wayland clients can set a NULL buffer as their cursor
* explicitly, which means that we shouldn't display anything.
* So, we can't simply store a NULL in window_cursor to
@ -49,27 +64,53 @@ struct _MetaCursorTracker {
MetaCursorReference *root_cursor;
/* The cursor from the X11 server. */
MetaCursorReference *xfixes_cursor;
MetaCursorReference *theme_cursors[META_CURSOR_LAST];
};
struct _MetaCursorTrackerClass {
GObjectClass parent_class;
void (*get_pointer) (MetaCursorTracker *tracker,
int *x,
int *y,
ClutterModifierType *mods);
void (*sync_cursor) (MetaCursorTracker *tracker);
void (*ensure_cursor) (MetaCursorTracker *tracker);
void (*load_cursor_pixels) (MetaCursorTracker *tracker,
MetaCursorReference *cursor,
uint8_t *pixels,
int width,
int height,
int rowstride,
uint32_t format);
void (*load_cursor_buffer) (MetaCursorTracker *tracker,
MetaCursorReference *cursor,
struct wl_resource *buffer);
};
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
XEvent *xevent);
void _meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
gboolean has_cursor,
MetaCursorReference *cursor);
void _meta_cursor_tracker_sync_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor);
void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor);
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
MetaCursorReference * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);
MetaCursorReference *
meta_cursor_tracker_get_cursor_from_theme (MetaCursorTracker *tracker,
MetaCursor cursor);
MetaCursorReference *
meta_cursor_tracker_get_cursor_from_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y);
#endif

View File

@ -1,8 +1,8 @@
/* -*- 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
@ -12,7 +12,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
@ -33,21 +33,12 @@
#include <meta/util.h>
#include <meta/errors.h>
#include <cogl/cogl.h>
#include <cogl/cogl-wayland-server.h>
#include <clutter/clutter.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include "meta-backend.h"
#include "meta-cursor-private.h"
#include "meta-cursor-tracker-private.h"
#include "backends/native/meta-cursor-tracker-native.h"
#include "backends/x11/meta-cursor-tracker-x11.h"
#include "screen-private.h"
#include "wayland/meta-wayland-private.h"
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
enum {
@ -57,46 +48,14 @@ enum {
static guint signals[LAST_SIGNAL];
static MetaCursorReference *
get_displayed_cursor (MetaCursorTracker *tracker)
{
if (!tracker->is_showing)
return NULL;
if (tracker->screen->display->grab_op == META_GRAB_OP_NONE)
{
if (tracker->has_window_cursor)
return tracker->window_cursor;
}
return tracker->root_cursor;
}
static void
update_displayed_cursor (MetaCursorTracker *tracker)
{
meta_cursor_renderer_set_cursor (tracker->renderer, tracker->displayed_cursor);
}
static void
sync_cursor (MetaCursorTracker *tracker)
{
MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker);
if (tracker->displayed_cursor == displayed_cursor)
return;
g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref);
if (displayed_cursor)
tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor);
update_displayed_cursor (tracker);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
}
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;
}
@ -104,15 +63,43 @@ static void
meta_cursor_tracker_finalize (GObject *object)
{
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
int i;
if (self->displayed_cursor)
meta_cursor_reference_unref (self->displayed_cursor);
if (self->root_cursor)
meta_cursor_reference_unref (self->root_cursor);
for (i = 0; i < META_CURSOR_LAST; i++)
if (self->theme_cursors[i])
meta_cursor_reference_unref (self->theme_cursors[i]);
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
}
static void
default_do_nothing (MetaCursorTracker *tracker)
{
}
static void
default_load_cursor_pixels (MetaCursorTracker *tracker,
MetaCursorReference *cursor,
uint8_t *pixels,
int width,
int height,
int rowstride,
uint32_t format)
{
}
static void
default_load_cursor_buffer (MetaCursorTracker *tracker,
MetaCursorReference *cursor,
struct wl_resource *buffer)
{
}
static void
meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
{
@ -120,6 +107,11 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
object_class->finalize = meta_cursor_tracker_finalize;
klass->sync_cursor = default_do_nothing;
klass->ensure_cursor = default_do_nothing;
klass->load_cursor_pixels = default_load_cursor_pixels;
klass->load_cursor_buffer = default_load_cursor_buffer;
signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@ -128,52 +120,6 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
G_TYPE_NONE, 0);
}
static MetaCursorTracker *
make_wayland_cursor_tracker (MetaScreen *screen)
{
MetaBackend *backend = meta_get_backend ();
MetaWaylandCompositor *compositor;
MetaCursorTracker *self;
self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
self->screen = screen;
self->renderer = meta_backend_get_cursor_renderer (backend);
compositor = meta_wayland_compositor_get_default ();
compositor->seat->pointer.cursor_tracker = self;
meta_cursor_tracker_update_position (self, 0, 0);
return self;
}
static MetaCursorTracker *
make_x11_cursor_tracker (MetaScreen *screen)
{
MetaBackend *backend = meta_get_backend ();
MetaCursorTracker *self;
self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
self->screen = screen;
self->renderer = meta_backend_get_cursor_renderer (backend);
XFixesSelectCursorInput (screen->display->xdisplay,
screen->xroot,
XFixesDisplayCursorNotifyMask);
return self;
}
static MetaCursorTracker *
meta_cursor_tracker_new (MetaScreen *screen)
{
if (meta_is_wayland_compositor ())
return make_wayland_cursor_tracker (screen);
else
return make_x11_cursor_tracker (screen);
}
static MetaCursorTracker *_cursor_tracker;
/**
* meta_cursor_tracker_get_for_screen:
* @screen: the #MetaScreen
@ -185,123 +131,18 @@ static MetaCursorTracker *_cursor_tracker;
MetaCursorTracker *
meta_cursor_tracker_get_for_screen (MetaScreen *screen)
{
if (!_cursor_tracker)
_cursor_tracker = meta_cursor_tracker_new (screen);
MetaCursorTracker *self;
return _cursor_tracker;
}
static void
set_window_cursor (MetaCursorTracker *tracker,
gboolean has_cursor,
MetaCursorReference *cursor)
{
g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref);
if (cursor)
tracker->window_cursor = meta_cursor_reference_ref (cursor);
tracker->has_window_cursor = has_cursor;
sync_cursor (tracker);
}
gboolean
meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
XEvent *xevent)
{
XFixesCursorNotifyEvent *notify_event;
if (screen->cursor_tracker)
return screen->cursor_tracker;
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->xfixes_cursor, meta_cursor_reference_unref);
return TRUE;
}
static MetaCursorReference *
meta_cursor_reference_take_texture (CoglTexture2D *texture,
int hot_x,
int hot_y)
{
MetaCursorReference *self;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->image.texture = texture;
self->image.hot_x = hot_x;
self->image.hot_y = hot_y;
return self;
}
static void
ensure_xfixes_cursor (MetaCursorTracker *tracker)
{
XFixesCursorImage *cursor_image;
CoglTexture2D *sprite;
guint8 *cursor_data;
gboolean free_cursor_data;
CoglContext *ctx;
if (tracker->xfixes_cursor)
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;
}
self = g_object_new (META_TYPE_CURSOR_TRACKER_NATIVE, NULL);
else
{
int i, j;
guint32 *cursor_words;
gulong *p;
guint32 *q;
self = g_object_new (META_TYPE_CURSOR_TRACKER_X11, NULL);
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,
cursor_image->width * 4, /* stride */
cursor_data,
NULL);
if (free_cursor_data)
g_free (cursor_data);
if (sprite != NULL)
{
MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite,
cursor_image->xhot,
cursor_image->yhot);
tracker->xfixes_cursor = cursor;
}
XFree (cursor_image);
screen->cursor_tracker = self;
return self;
}
/**
@ -312,22 +153,12 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
CoglTexture *
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
{
MetaCursorReference *cursor;
g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
if (meta_is_wayland_compositor ())
{
cursor = tracker->displayed_cursor;
}
else
{
ensure_xfixes_cursor (tracker);
cursor = tracker->xfixes_cursor;
}
META_CURSOR_TRACKER_GET_CLASS (tracker)->ensure_cursor (tracker);
if (cursor)
return meta_cursor_reference_get_cogl_texture (cursor, NULL, NULL);
if (tracker->current_cursor)
return meta_cursor_reference_get_cogl_texture (tracker->current_cursor, NULL, NULL);
else
return NULL;
}
@ -344,22 +175,12 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
int *x,
int *y)
{
MetaCursorReference *cursor;
g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
if (meta_is_wayland_compositor ())
{
cursor = tracker->displayed_cursor;
}
else
{
ensure_xfixes_cursor (tracker);
cursor = tracker->xfixes_cursor;
}
META_CURSOR_TRACKER_GET_CLASS (tracker)->ensure_cursor (tracker);
if (cursor)
meta_cursor_reference_get_cogl_texture (cursor, x, y);
if (tracker->current_cursor)
meta_cursor_reference_get_cogl_texture (tracker->current_cursor, x, y);
else
{
if (x)
@ -369,17 +190,41 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
}
}
void
_meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
gboolean has_cursor,
MetaCursorReference *cursor)
{
g_clear_pointer (&tracker->window_cursor, meta_cursor_reference_unref);
if (cursor)
tracker->window_cursor = meta_cursor_reference_ref (cursor);
tracker->has_window_cursor = has_cursor;
_meta_cursor_tracker_sync_cursor (tracker);
}
void
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor)
{
set_window_cursor (tracker, TRUE, cursor);
_meta_cursor_tracker_set_window_cursor (tracker, TRUE, cursor);
}
void
meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker)
{
set_window_cursor (tracker, FALSE, NULL);
_meta_cursor_tracker_set_window_cursor (tracker, FALSE, NULL);
}
void
meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor)
{
g_clear_pointer (&tracker->grab_cursor, meta_cursor_reference_unref);
if (cursor)
tracker->grab_cursor = meta_cursor_reference_ref (cursor);
_meta_cursor_tracker_sync_cursor (tracker);
}
void
@ -390,57 +235,53 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
if (cursor)
tracker->root_cursor = meta_cursor_reference_ref (cursor);
sync_cursor (tracker);
_meta_cursor_tracker_sync_cursor (tracker);
}
static MetaCursorReference *
get_current_cursor (MetaCursorTracker *tracker)
{
if (tracker->grab_cursor)
return tracker->grab_cursor;
if (tracker->has_window_cursor)
return tracker->window_cursor;
return tracker->root_cursor;
}
static MetaCursorReference *
get_displayed_cursor (MetaCursorTracker *tracker)
{
if (!tracker->is_showing)
return NULL;
return get_current_cursor (tracker);
}
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y)
_meta_cursor_tracker_sync_cursor (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
MetaCursorReference *current_cursor = get_current_cursor (tracker);
MetaCursorReference *displayed_cursor = get_displayed_cursor (tracker);
meta_cursor_renderer_set_position (tracker->renderer, new_x, new_y);
}
if (tracker->displayed_cursor != displayed_cursor)
{
g_clear_pointer (&tracker->displayed_cursor, meta_cursor_reference_unref);
if (displayed_cursor)
tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor);
static void
get_pointer_position_gdk (int *x,
int *y,
int *mods)
{
GdkDeviceManager *gmanager;
GdkDevice *gdevice;
GdkScreen *gscreen;
META_CURSOR_TRACKER_GET_CLASS (tracker)->sync_cursor (tracker);
}
gmanager = gdk_display_get_device_manager (gdk_display_get_default ());
gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);
if (tracker->current_cursor != current_cursor)
{
g_clear_pointer (&tracker->current_cursor, meta_cursor_reference_unref);
if (current_cursor)
tracker->current_cursor = meta_cursor_reference_ref (current_cursor);
gdk_device_get_position (gdevice, &gscreen, x, y);
if (mods)
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
}
static void
get_pointer_position_clutter (int *x,
int *y,
int *mods)
{
ClutterDeviceManager *cmanager;
ClutterInputDevice *cdevice;
ClutterPoint point;
cmanager = clutter_device_manager_get_default ();
cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE);
clutter_input_device_get_coords (cdevice, NULL, &point);
if (x)
*x = point.x;
if (y)
*y = point.y;
if (mods)
*mods = clutter_input_device_get_modifier_state (cdevice);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
}
}
void
@ -449,15 +290,7 @@ meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
int *y,
ClutterModifierType *mods)
{
/* We can't use the clutter interface when not running as a wayland compositor,
because we need to query the server, rather than using the last cached value.
OTOH, on wayland we can't use GDK, because that only sees the events
we forward to xwayland.
*/
if (meta_is_wayland_compositor ())
get_pointer_position_clutter (x, y, (int*)mods);
else
get_pointer_position_gdk (x, y, (int*)mods);
META_CURSOR_TRACKER_GET_CLASS (tracker)->get_pointer (tracker, x, y, mods);
}
void
@ -468,11 +301,51 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
return;
tracker->is_showing = visible;
sync_cursor (tracker);
_meta_cursor_tracker_sync_cursor (tracker);
}
MetaCursorReference *
meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker)
meta_cursor_tracker_get_cursor_from_theme (MetaCursorTracker *tracker,
MetaCursor meta_cursor)
{
return tracker->displayed_cursor;
MetaCursorReference *cursor;
XcursorImage *xc_image;
if (tracker->theme_cursors[meta_cursor])
return meta_cursor_reference_ref (tracker->theme_cursors[meta_cursor]);
xc_image = meta_display_load_x_cursor (meta_get_display (), meta_cursor);
if (!xc_image)
return NULL;
cursor = meta_cursor_reference_from_xcursor_image (xc_image);
META_CURSOR_TRACKER_GET_CLASS (tracker)->load_cursor_pixels (tracker,
cursor,
(uint8_t *) xc_image->pixels,
xc_image->width,
xc_image->height,
xc_image->width * 4,
GBM_FORMAT_ARGB8888);
XcursorImageDestroy (xc_image);
tracker->theme_cursors[meta_cursor] = cursor;
return meta_cursor_reference_ref (cursor);
}
MetaCursorReference *
meta_cursor_tracker_get_cursor_from_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
MetaCursorReference *cursor;
cursor = meta_cursor_reference_from_buffer (buffer, hot_x, hot_y);
META_CURSOR_TRACKER_GET_CLASS (tracker)->load_cursor_buffer (tracker,
cursor,
buffer);
return cursor;
}

View File

@ -27,17 +27,23 @@
#include "display-private.h"
#include "screen-private.h"
#include "meta-backend.h"
#include "backends/native/meta-cursor-renderer-native.h"
#include "meta-cursor-tracker-private.h"
#include <string.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
#include <cogl/cogl-wayland-server.h>
static MetaCursorReference *
meta_cursor_reference_new (void)
{
MetaCursorReference *self;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
return self;
}
MetaCursorReference *
meta_cursor_reference_ref (MetaCursorReference *self)
{
@ -71,77 +77,141 @@ meta_cursor_reference_unref (MetaCursorReference *self)
meta_cursor_reference_free (self);
}
static const char *
translate_meta_cursor (MetaCursor cursor)
static void
translate_meta_cursor (MetaCursor cursor,
guint *glyph_out,
const char **name_out)
{
guint glyph = XC_num_glyphs;
const char *name = NULL;
switch (cursor)
{
case META_CURSOR_DEFAULT:
return "left_ptr";
glyph = XC_left_ptr;
break;
case META_CURSOR_NORTH_RESIZE:
return "top_side";
glyph = XC_top_side;
break;
case META_CURSOR_SOUTH_RESIZE:
return "bottom_side";
glyph = XC_bottom_side;
break;
case META_CURSOR_WEST_RESIZE:
return "left_side";
glyph = XC_left_side;
break;
case META_CURSOR_EAST_RESIZE:
return "right_side";
glyph = XC_right_side;
break;
case META_CURSOR_SE_RESIZE:
return "bottom_right_corner";
glyph = XC_bottom_right_corner;
break;
case META_CURSOR_SW_RESIZE:
return "bottom_left_corner";
glyph = XC_bottom_left_corner;
break;
case META_CURSOR_NE_RESIZE:
return "top_right_corner";
glyph = XC_top_right_corner;
break;
case META_CURSOR_NW_RESIZE:
return "top_left_corner";
glyph = XC_top_left_corner;
break;
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
return "fleur";
glyph = XC_fleur;
break;
case META_CURSOR_BUSY:
return "watch";
glyph = XC_watch;
break;
case META_CURSOR_DND_IN_DRAG:
return "dnd-none";
name = "dnd-none";
break;
case META_CURSOR_DND_MOVE:
return "dnd-move";
name = "dnd-move";
break;
case META_CURSOR_DND_COPY:
return "dnd-copy";
name = "dnd-copy";
break;
case META_CURSOR_DND_UNSUPPORTED_TARGET:
return "dnd-none";
name = "dnd-none";
break;
case META_CURSOR_POINTING_HAND:
return "hand2";
glyph = XC_hand2;
break;
case META_CURSOR_CROSSHAIR:
return "crosshair";
glyph = XC_crosshair;
break;
case META_CURSOR_IBEAM:
return "xterm";
glyph = XC_xterm;
break;
default:
g_assert_not_reached ();
glyph = 0; /* silence compiler */
break;
}
g_assert_not_reached ();
*glyph_out = glyph;
*name_out = name;
}
static Cursor
load_cursor_on_server (MetaDisplay *display,
MetaCursor cursor)
{
Cursor xcursor;
guint glyph;
const char *name;
translate_meta_cursor (cursor, &glyph, &name);
if (name != NULL)
xcursor = XcursorLibraryLoadCursor (display->xdisplay, name);
else
xcursor = XCreateFontCursor (display->xdisplay, glyph);
return xcursor;
}
Cursor
meta_cursor_create_x_cursor (Display *xdisplay,
MetaCursor cursor)
meta_display_create_x_cursor (MetaDisplay *display,
MetaCursor cursor)
{
return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
return load_cursor_on_server (display, cursor);
}
static XcursorImage *
load_cursor_on_client (MetaCursor cursor)
load_cursor_on_client (MetaDisplay *display,
MetaCursor cursor)
{
return XcursorLibraryLoadImage (translate_meta_cursor (cursor),
meta_prefs_get_cursor_theme (),
meta_prefs_get_cursor_size ());
XcursorImage *image;
guint glyph;
const char *name;
const char *theme = XcursorGetTheme (display->xdisplay);
int size = XcursorGetDefaultSize (display->xdisplay);
translate_meta_cursor (cursor, &glyph, &name);
if (name != NULL)
image = XcursorLibraryLoadImage (name, theme, size);
else
image = XcursorShapeLoadImage (glyph, theme, size);
return image;
}
static void
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
MetaCursorImage *image,
uint8_t *pixels,
int width,
int height,
int rowstride,
uint32_t gbm_format)
XcursorImage *
meta_display_load_x_cursor (MetaDisplay *display,
MetaCursor cursor)
{
return load_cursor_on_client (display, cursor);
}
void
meta_cursor_reference_load_gbm_buffer (MetaCursorReference *cursor,
struct gbm_device *gbm,
uint8_t *pixels,
int width,
int height,
int rowstride,
uint32_t gbm_format)
{
if (width > 64 || height > 64)
{
@ -155,176 +225,132 @@ meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
uint8_t buf[4 * 64 * 64];
int i;
image->bo = gbm_bo_create (gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
cursor->image.bo = gbm_bo_create (gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * 64, pixels + i * rowstride, width * 4);
gbm_bo_write (image->bo, buf, 64 * 64 * 4);
gbm_bo_write (cursor->image.bo, buf, 64 * 64 * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
static struct gbm_device *
get_gbm_device (void)
void
meta_cursor_reference_import_gbm_buffer (MetaCursorReference *cursor,
struct gbm_device *gbm,
struct wl_resource *buffer,
int width,
int height)
{
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
/* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
that, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
if (width != 64 || height != 64)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
else
return NULL;
cursor->image.bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (!cursor->image.bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
static void
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
XcursorImage *xc_image)
MetaCursorReference *
meta_cursor_reference_from_xfixes_cursor_image (XFixesCursorImage *cursor_image)
{
MetaCursorReference *cursor;
CoglTexture2D *sprite;
CoglContext *ctx;
guint8 *cursor_data;
gboolean free_cursor_data;
cursor = meta_cursor_reference_new ();
/* 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,
cursor_image->width * 4, /* stride */
cursor_data,
NULL);
if (free_cursor_data)
g_free (cursor_data);
cursor->image.texture = sprite;
cursor->image.hot_x = cursor_image->xhot;
cursor->image.hot_y = cursor_image->yhot;
return cursor;
}
MetaCursorReference *
meta_cursor_reference_from_xcursor_image (XcursorImage *xc_image)
{
MetaCursorReference *cursor;
int width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
struct gbm_device *gbm;
cursor = meta_cursor_reference_new ();
width = xc_image->width;
height = xc_image->height;
rowstride = width * 4;
gbm_format = GBM_FORMAT_ARGB8888;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
#else
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
#endif
image->hot_x = xc_image->xhot;
image->hot_y = xc_image->yhot;
cursor->image.hot_x = xc_image->xhot;
cursor->image.hot_y = xc_image->yhot;
clutter_backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
image->texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
rowstride,
(uint8_t *) xc_image->pixels,
NULL);
gbm = get_gbm_device ();
if (gbm)
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) xc_image->pixels,
width, height, rowstride,
gbm_format);
}
MetaCursorReference *
meta_cursor_reference_from_theme (MetaCursor cursor)
{
MetaCursorReference *self;
XcursorImage *image;
image = load_cursor_on_client (cursor);
if (!image)
return NULL;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->cursor = cursor;
meta_cursor_image_load_from_xcursor_image (&self->image, image);
XcursorImageDestroy (image);
return self;
}
static void
meta_cursor_image_load_from_buffer (MetaCursorImage *image,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
struct gbm_device *gbm = get_gbm_device ();
ClutterBackend *backend;
CoglContext *cogl_context;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
int width, height;
image->hot_x = hot_x;
image->hot_y = hot_y;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
if (gbm)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#else
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#endif
default:
g_warn_if_reached ();
gbm_format = GBM_FORMAT_ARGB8888;
}
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) wl_shm_buffer_get_data (shm_buffer),
width, height, rowstride,
gbm_format);
}
}
else
{
/* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
that, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
if (width != 64 || height != 64)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
if (gbm)
{
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (!image->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
}
cursor->image.texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
rowstride,
(uint8_t *) xc_image->pixels,
NULL);
return cursor;
}
MetaCursorReference *
@ -332,13 +358,21 @@ meta_cursor_reference_from_buffer (struct wl_resource *buffer,
int hot_x,
int hot_y)
{
MetaCursorReference *self;
MetaCursorReference *cursor;
ClutterBackend *backend;
CoglContext *cogl_context;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
meta_cursor_image_load_from_buffer (&self->image, buffer, hot_x, hot_y);
cursor = meta_cursor_reference_new ();
return self;
cursor->image.hot_x = hot_x;
cursor->image.hot_y = hot_y;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cursor->image.texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
return cursor;
}
CoglTexture *
@ -364,9 +398,3 @@ meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
*hot_y = cursor->image.hot_y;
return cursor->image.bo;
}
MetaCursor
meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor)
{
return cursor->cursor;
}

View File

@ -27,18 +27,4 @@ typedef struct _MetaCursorReference MetaCursorReference;
MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor);
void meta_cursor_reference_unref (MetaCursorReference *cursor);
#include <meta/common.h>
#include <wayland-server.h>
MetaCursorReference * meta_cursor_reference_from_theme (MetaCursor cursor);
MetaCursorReference * meta_cursor_reference_from_buffer (struct wl_resource *buffer,
int hot_x,
int hot_y);
MetaCursor meta_cursor_reference_get_meta_cursor (MetaCursorReference *cursor);
Cursor meta_cursor_create_x_cursor (Display *xdisplay,
MetaCursor cursor);
#endif /* META_CURSOR_H */

View File

@ -1,7 +1,7 @@
/* -*- 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
@ -11,7 +11,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/

View File

@ -180,9 +180,6 @@ create_monitor_skeleton (GDBusObjectManagerServer *manager,
meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
g_object_unref (skeleton);
g_object_unref (object);
}
static void

View File

@ -1,8 +1,8 @@
/* -*- 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
@ -12,7 +12,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*

View File

@ -1,8 +1,8 @@
/* -*- 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
@ -12,7 +12,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
@ -38,7 +38,8 @@
#include <meta/meta-idle-monitor.h>
#include "meta-idle-monitor-private.h"
#include "meta-idle-monitor-dbus.h"
#include "meta-backend.h"
#include "backends/x11/meta-idle-monitor-xsync.h"
#include "backends/native/meta-idle-monitor-native.h"
G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
@ -53,6 +54,9 @@ 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;
void
_meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch)
{
@ -156,6 +160,36 @@ meta_idle_monitor_init (MetaIdleMonitor *monitor)
{
}
static GType
get_idle_monitor_type (void)
{
if (meta_is_wayland_compositor ())
return META_TYPE_IDLE_MONITOR_NATIVE;
else
return META_TYPE_IDLE_MONITOR_XSYNC;
}
static void
ensure_device_monitor (int device_id)
{
if (device_monitors[device_id])
return;
device_monitors[device_id] = g_object_new (get_idle_monitor_type (),
"device-id", device_id,
NULL);
device_id_max = MAX (device_id_max, device_id);
}
/* FIXME -- destroy device monitors at some point */
G_GNUC_UNUSED static void
destroy_device_monitor (int device_id)
{
g_clear_object (&device_monitors[device_id]);
if (device_id == device_id_max)
device_id_max--;
}
/**
* meta_idle_monitor_get_core:
*
@ -166,8 +200,8 @@ meta_idle_monitor_init (MetaIdleMonitor *monitor)
MetaIdleMonitor *
meta_idle_monitor_get_core (void)
{
MetaBackend *backend = meta_get_backend ();
return meta_backend_get_idle_monitor (backend, 0);
ensure_device_monitor (0);
return device_monitors[0];
}
/**
@ -181,8 +215,10 @@ meta_idle_monitor_get_core (void)
MetaIdleMonitor *
meta_idle_monitor_get_for_device (int device_id)
{
MetaBackend *backend = meta_get_backend ();
return meta_backend_get_idle_monitor (backend, 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 MetaIdleMonitorWatch *
@ -316,3 +352,16 @@ meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
{
return META_IDLE_MONITOR_GET_CLASS (monitor)->get_idletime (monitor);
}
void
meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent)
{
int i;
if (meta_is_wayland_compositor ())
return;
for (i = 0; i <= device_id_max; i++)
if (device_monitors[i])
meta_idle_monitor_xsync_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent);
}

View File

@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
@ -8,7 +8,7 @@
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -18,7 +18,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
@ -78,7 +78,6 @@ struct _MetaMonitorConfig {
GHashTable *configs;
MetaConfiguration *current;
gboolean current_is_stored;
gboolean current_is_for_laptop_lid;
MetaConfiguration *previous;
GFile *file;
@ -571,7 +570,7 @@ is_all_whitespace (const char *text,
gsize text_len)
{
gsize i;
for (i = 0; i < text_len; i++)
if (!g_ascii_isspace (text[i]))
return FALSE;
@ -841,9 +840,6 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
MetaConfiguration key;
MetaConfiguration *stored;
if (n_outputs == 0)
return NULL;
make_config_key (&key, outputs, n_outputs, -1);
stored = g_hash_table_lookup (self->configs, &key);
@ -878,8 +874,7 @@ apply_configuration (MetaMonitorConfig *self,
/* Stored (persistent) configurations override the previous one always.
Also, we clear the previous configuration if the current one (which is
about to become previous) is stored, or if the current one has
different outputs.
about to become previous) is stored.
*/
if (stored ||
(self->current && self->current_is_stored))
@ -890,27 +885,11 @@ apply_configuration (MetaMonitorConfig *self,
}
else
{
/* Despite the name, config_equal() only checks the set of outputs,
not their modes
*/
if (self->current && config_equal (self->current, config))
{
self->previous = self->current;
}
else
{
if (self->current)
config_free (self->current);
self->previous = NULL;
}
self->previous = self->current;
}
self->current = config;
self->current_is_stored = stored;
/* If true, we'll be overridden at the end of this call
inside turn_off_laptop_display()
*/
self->current_is_for_laptop_lid = FALSE;
if (self->current == self->previous)
self->previous = NULL;
@ -1027,16 +1006,8 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
if (self->lid_is_closed &&
stored->n_outputs > 1 &&
laptop_display_is_on (stored))
{
if (apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE))
{
self->current_is_for_laptop_lid = TRUE;
return TRUE;
}
else
return FALSE;
}
return apply_configuration (self, make_laptop_lid_config (stored),
manager, FALSE);
else
return apply_configuration (self, stored, manager, TRUE);
}
@ -1276,12 +1247,6 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
meta_monitor_manager_get_screen_limits (manager, &max_width, &max_height);
if (n_outputs == 0)
{
meta_verbose ("No output connected, not applying configuration\n");
return;
}
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
if (default_config != NULL)
@ -1383,7 +1348,6 @@ turn_off_laptop_display (MetaMonitorConfig *self,
new = make_laptop_lid_config (self->current);
apply_configuration (self, new, manager, FALSE);
self->current_is_for_laptop_lid = TRUE;
}
static void
@ -1403,7 +1367,7 @@ power_client_changed_cb (UpClient *client,
if (is_closed)
turn_off_laptop_display (self, manager);
else if (self->current_is_for_laptop_lid)
else
meta_monitor_config_restore_previous (self, manager);
}
}

View File

@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
@ -8,7 +8,7 @@
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -18,7 +18,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
@ -36,8 +36,9 @@
#include "util-private.h"
#include <meta/errors.h>
#include "meta-monitor-config.h"
#include "backends/native/meta-monitor-manager-kms.h"
#include "backends/x11/meta-monitor-manager-xrandr.h"
#include "meta-backend.h"
#include "meta-monitor-manager-dummy.h"
enum {
CONFIRM_DISPLAY_CHANGE,
@ -167,6 +168,58 @@ make_logical_config (MetaMonitorManager *manager)
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
}
static GType
get_default_backend (void)
{
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
return META_TYPE_MONITOR_MANAGER_KMS;
#endif
#if defined(CLUTTER_WINDOWING_X11)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
{
/* If we're a Wayland compositor using the X11 backend,
* we're a nested configuration, so return the dummy
* monitor setup. */
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER_DUMMY;
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
#endif
#if defined(CLUTTER_WINDOWING_WAYLAND)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND))
{
/* Use the dummy implementation on Wayland for now.
* In the future, we should support wl_fullscreen_output
* which will have CRTC management in the protocol. */
return META_TYPE_MONITOR_MANAGER_DUMMY;
}
#endif
g_assert_not_reached ();
}
static MetaMonitorManager *
meta_monitor_manager_new (void)
{
const char *env;
GType type;
env = g_getenv ("META_DEBUG_MULTIMONITOR");
if (env == NULL)
type = get_default_backend ();
else if (strcmp (env, "xrandr") == 0)
type = META_TYPE_MONITOR_MANAGER_XRANDR;
else
type = META_TYPE_MONITOR_MANAGER;
return g_object_new (type, NULL);
}
static void
meta_monitor_manager_constructed (GObject *object)
{
@ -483,13 +536,13 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
i, /* ID */
(gint64)crtc->crtc_id,
crtc->crtc_id,
(int)crtc->rect.x,
(int)crtc->rect.y,
(int)crtc->rect.width,
(int)crtc->rect.height,
(int)(crtc->current_mode ? crtc->current_mode - manager->modes : -1),
(guint32)crtc->transform,
crtc->transform,
&transforms,
NULL /* properties */);
}
@ -560,7 +613,7 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
i, /* ID */
(gint64)output->output_id,
output->output_id,
(int)(output->crtc ? output->crtc - manager->crtcs : -1),
&crtcs,
output->name,
@ -575,9 +628,9 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_builder_add (&mode_builder, "(uxuud)",
i, /* ID */
(gint64)mode->mode_id,
(guint32)mode->width,
(guint32)mode->height,
mode->mode_id,
mode->width,
mode->height,
(double)mode->refresh_rate);
}
@ -852,7 +905,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
/* If we were in progress of making a persistent change and we see a
new request, it's likely that the old one failed in some way, so
don't save it, but also don't queue for restoring it.
*/
*/
if (manager->persistent_timeout_id && persistent)
{
g_source_remove (manager->persistent_timeout_id);
@ -878,7 +931,6 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
if (persistent)
{
manager->persistent_timeout_id = g_timeout_add_seconds (20, save_config_timeout, manager);
g_source_set_name_by_id (manager->persistent_timeout_id, "[mutter] save_config_timeout");
g_signal_emit (manager, signals[CONFIRM_DISPLAY_CHANGE], 0);
}
@ -1126,12 +1178,20 @@ initialize_dbus_interface (MetaMonitorManager *manager)
g_object_unref);
}
static MetaMonitorManager *global_monitor_manager;
void
meta_monitor_manager_initialize (void)
{
global_monitor_manager = meta_monitor_manager_new ();
}
MetaMonitorManager *
meta_monitor_manager_get (void)
{
MetaBackend *backend = meta_get_backend ();
g_assert (global_monitor_manager != NULL);
return meta_backend_get_monitor_manager (backend);
return global_monitor_manager;
}
MetaMonitorInfo *
@ -1217,3 +1277,16 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
g_free (old_monitor_infos);
}
gboolean
meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
XEvent *event)
{
MetaMonitorManagerClass *klass;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->handle_xevent)
return klass->handle_xevent (manager, event);
else
return FALSE;
}

View File

@ -12,12 +12,12 @@
* at MetaScreen instead.
*/
/*
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -27,7 +27,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
@ -46,7 +46,6 @@
#include "meta-display-config-shared.h"
#include "meta-dbus-display-config.h"
#include "meta-cursor.h"
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
typedef struct _MetaMonitorManager MetaMonitorManager;
@ -73,7 +72,6 @@ struct _MetaOutput
int width_mm;
int height_mm;
CoglSubpixelOrder subpixel_order;
int scale;
MetaMonitorMode *preferred_mode;
MetaMonitorMode **modes;
@ -125,7 +123,8 @@ struct _MetaCRTC
/* Used when changing configuration */
gboolean is_dirty;
MetaCursorReference *cursor;
/* Updated by MetaCursorTracker */
gboolean has_hw_cursor;
};
struct _MetaMonitorMode
@ -286,10 +285,14 @@ struct _MetaMonitorManagerClass
unsigned short *,
unsigned short *,
unsigned short *);
gboolean (*handle_xevent) (MetaMonitorManager *,
XEvent *);
};
GType meta_monitor_manager_get_type (void);
void meta_monitor_manager_initialize (void);
MetaMonitorManager *meta_monitor_manager_get (void);
void meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager);
@ -310,6 +313,9 @@ void meta_monitor_manager_get_resources (MetaMonitorManager
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
gboolean meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
XEvent *event);
void meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
int *width,
int *height);

View File

@ -1,107 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "dbus-utils.h"
#include <glib.h>
/* Stolen from tp_escape_as_identifier, from tp-glib,
* which follows the same escaping convention as systemd.
*/
static inline gboolean
_esc_ident_bad (gchar c, gboolean is_first)
{
return ((c < 'a' || c > 'z') &&
(c < 'A' || c > 'Z') &&
(c < '0' || c > '9' || is_first));
}
static gchar *
escape_dbus_component (const gchar *name)
{
gboolean bad = FALSE;
size_t len = 0;
GString *op;
const gchar *ptr, *first_ok;
g_return_val_if_fail (name != NULL, NULL);
/* fast path for empty name */
if (name[0] == '\0')
return g_strdup ("_");
for (ptr = name; *ptr; ptr++)
{
if (_esc_ident_bad (*ptr, ptr == name))
{
bad = TRUE;
len += 3;
}
else
len++;
}
/* fast path if it's clean */
if (!bad)
return g_strdup (name);
/* If strictly less than ptr, first_ok is the first uncopied safe character.
*/
first_ok = name;
op = g_string_sized_new (len);
for (ptr = name; *ptr; ptr++)
{
if (_esc_ident_bad (*ptr, ptr == name))
{
/* copy preceding safe characters if any */
if (first_ok < ptr)
{
g_string_append_len (op, first_ok, ptr - first_ok);
}
/* escape the unsafe character */
g_string_append_printf (op, "_%02x", (unsigned char)(*ptr));
/* restart after it */
first_ok = ptr + 1;
}
}
/* copy trailing safe characters if any */
if (first_ok < ptr)
{
g_string_append_len (op, first_ok, ptr - first_ok);
}
return g_string_free (op, FALSE);
}
char *
get_escaped_dbus_path (const char *prefix,
const char *component)
{
char *escaped_component = escape_dbus_component (component);
char *path = g_strconcat (prefix, "/", escaped_component, NULL);
g_free (escaped_component);
return path;
}

View File

@ -1,32 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef DBUS_UTILS_H
#define DBUS_UTILS_H
char *
get_escaped_dbus_path (const char *prefix,
const char *component);
#endif /* DBUS_UTILS_H */

View File

@ -1,235 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include <meta/main.h>
#include <clutter/evdev/clutter-evdev.h>
#include "meta-backend-native.h"
#include "meta-idle-monitor-native.h"
#include "meta-monitor-manager-kms.h"
#include "meta-cursor-renderer-native.h"
#include "meta-launcher.h"
struct _MetaBackendNativePrivate
{
MetaLauncher *launcher;
};
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendNative, meta_backend_native, META_TYPE_BACKEND);
/*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
*
* Copyright © 2006 Keith Packard
* Copyright 2010 Red Hat, Inc
*
*/
static gboolean
check_all_screen_monitors(MetaMonitorInfo *monitors,
unsigned n_monitors,
float x,
float y)
{
unsigned int i;
for (i = 0; i < n_monitors; i++)
{
MetaMonitorInfo *monitor = &monitors[i];
int left, right, top, bottom;
left = monitor->rect.x;
right = left + monitor->rect.width;
top = monitor->rect.y;
bottom = left + monitor->rect.height;
if ((x >= left) && (x < right) && (y >= top) && (y < bottom))
return TRUE;
}
return FALSE;
}
static void
constrain_all_screen_monitors (ClutterInputDevice *device,
MetaMonitorInfo *monitors,
unsigned n_monitors,
float *x,
float *y)
{
ClutterPoint current;
unsigned int i;
clutter_input_device_get_coords (device, NULL, &current);
/* if we're trying to escape, clamp to the CRTC we're coming from */
for (i = 0; i < n_monitors; i++)
{
MetaMonitorInfo *monitor = &monitors[i];
int left, right, top, bottom;
float nx, ny;
left = monitor->rect.x;
right = left + monitor->rect.width;
top = monitor->rect.y;
bottom = left + monitor->rect.height;
nx = current.x;
ny = current.y;
if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom))
{
if (*x < left)
*x = left;
if (*x >= right)
*x = right - 1;
if (*y < top)
*y = top;
if (*y >= bottom)
*y = bottom - 1;
return;
}
}
}
static void
pointer_constrain_callback (ClutterInputDevice *device,
guint32 time,
float *new_x,
float *new_y,
gpointer user_data)
{
MetaMonitorManager *monitor_manager;
MetaMonitorInfo *monitors;
unsigned int n_monitors;
gboolean ret;
monitor_manager = meta_monitor_manager_get ();
monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
/* if we're moving inside a monitor, we're fine */
ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y);
if (ret == TRUE)
return;
/* if we're trying to escape, clamp to the CRTC we're coming from */
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
}
static void
meta_backend_native_post_init (MetaBackend *backend)
{
ClutterDeviceManager *manager = clutter_device_manager_get_default ();
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
NULL, NULL);
}
static MetaIdleMonitor *
meta_backend_native_create_idle_monitor (MetaBackend *backend,
int device_id)
{
return g_object_new (META_TYPE_IDLE_MONITOR_NATIVE,
"device-id", device_id,
NULL);
}
static MetaMonitorManager *
meta_backend_native_create_monitor_manager (MetaBackend *backend)
{
return g_object_new (META_TYPE_MONITOR_MANAGER_KMS, NULL);
}
static MetaCursorRenderer *
meta_backend_native_create_cursor_renderer (MetaBackend *backend)
{
return g_object_new (META_TYPE_CURSOR_RENDERER_NATIVE, NULL);
}
static void
meta_backend_native_class_init (MetaBackendNativeClass *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
backend_class->post_init = meta_backend_native_post_init;
backend_class->create_idle_monitor = meta_backend_native_create_idle_monitor;
backend_class->create_monitor_manager = meta_backend_native_create_monitor_manager;
backend_class->create_cursor_renderer = meta_backend_native_create_cursor_renderer;
}
static void
meta_backend_native_init (MetaBackendNative *native)
{
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
/* We're a display server, so start talking to weston-launch. */
priv->launcher = meta_launcher_new ();
}
gboolean
meta_activate_vt (int vt, GError **error)
{
MetaBackend *backend = meta_get_backend ();
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
return meta_launcher_activate_vt (priv->launcher, vt, error);
}
/**
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* Wayland compositor, this tells logind to switch over to
* the new session.
*/
gboolean
meta_activate_session (void)
{
GError *error = NULL;
MetaBackend *backend = meta_get_backend ();
/* Do nothing. */
if (!META_IS_BACKEND_NATIVE (backend))
return TRUE;
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
if (!meta_launcher_activate_session (priv->launcher, &error))
{
g_warning ("Could not activate session: %s\n", error->message);
g_error_free (error);
return FALSE;
}
return TRUE;
}

View File

@ -1,54 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_BACKEND_NATIVE_H
#define META_BACKEND_NATIVE_H
#include "backends/meta-backend-private.h"
#define META_TYPE_BACKEND_NATIVE (meta_backend_native_get_type ())
#define META_BACKEND_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKEND_NATIVE, MetaBackendNative))
#define META_BACKEND_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKEND_NATIVE, MetaBackendNativeClass))
#define META_IS_BACKEND_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKEND_NATIVE))
#define META_IS_BACKEND_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKEND_NATIVE))
#define META_BACKEND_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKEND_NATIVE, MetaBackendNativeClass))
typedef struct _MetaBackendNative MetaBackendNative;
typedef struct _MetaBackendNativeClass MetaBackendNativeClass;
struct _MetaBackendNative
{
MetaBackend parent;
};
struct _MetaBackendNativeClass
{
MetaBackendClass parent_class;
};
GType meta_backend_native_get_type (void) G_GNUC_CONST;
gboolean meta_activate_vt (int vt, GError **error);
#endif /* META_BACKEND_NATIVE_H */

View File

@ -1,205 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-cursor-renderer-native.h"
#include <gbm.h>
#include "meta-cursor-private.h"
#include "meta-monitor-manager.h"
struct _MetaCursorRendererNativePrivate
{
gboolean has_hw_cursor;
int drm_fd;
struct gbm_device *gbm;
};
typedef struct _MetaCursorRendererNativePrivate MetaCursorRendererNativePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
static void
meta_cursor_renderer_native_finalize (GObject *object)
{
MetaCursorRendererNative *renderer = META_CURSOR_RENDERER_NATIVE (object);
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (renderer);
if (priv->gbm)
gbm_device_destroy (priv->gbm);
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
}
static void
set_crtc_cursor (MetaCursorRendererNative *native,
MetaCRTC *crtc,
MetaCursorReference *cursor,
gboolean force)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
if (crtc->cursor == cursor && !force)
return;
crtc->cursor = cursor;
if (cursor)
{
struct gbm_bo *bo;
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
bo = meta_cursor_reference_get_gbm_bo (cursor, &hot_x, &hot_y);
handle = gbm_bo_get_handle (bo);
width = gbm_bo_get_width (bo);
height = gbm_bo_get_height (bo);
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
}
else
{
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
}
}
static void
update_hw_cursor (MetaCursorRendererNative *native,
gboolean force)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
const MetaRectangle *cursor_rect = meta_cursor_renderer_get_rect (renderer);
MetaCursorReference *cursor = meta_cursor_renderer_get_cursor (renderer);
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
for (i = 0; i < n_crtcs; i++)
{
gboolean crtc_should_have_cursor;
MetaCursorReference *crtc_cursor;
MetaRectangle *crtc_rect;
crtc_rect = &crtcs[i].rect;
crtc_should_have_cursor = (priv->has_hw_cursor && meta_rectangle_overlap (cursor_rect, crtc_rect));
if (crtc_should_have_cursor)
crtc_cursor = cursor;
else
crtc_cursor = NULL;
set_crtc_cursor (native, &crtcs[i], crtc_cursor, force);
if (crtc_cursor)
{
drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id,
cursor_rect->x - crtc_rect->x,
cursor_rect->y - crtc_rect->y);
}
}
}
static gboolean
should_have_hw_cursor (MetaCursorRenderer *renderer)
{
MetaCursorReference *cursor = meta_cursor_renderer_get_cursor (renderer);
if (cursor)
return (meta_cursor_reference_get_gbm_bo (cursor, NULL, NULL) != NULL);
else
return FALSE;
}
static gboolean
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
priv->has_hw_cursor = should_have_hw_cursor (renderer);
update_hw_cursor (native, FALSE);
return priv->has_hw_cursor;
}
static void
meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
{
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_cursor_renderer_native_finalize;
renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
}
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaCursorRendererNative *native)
{
/* Our tracking is all messed up, so force an update. */
update_hw_cursor (native, TRUE);
}
static void
meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
MetaMonitorManager *monitors;
monitors = meta_monitor_manager_get ();
g_signal_connect_object (monitors, "monitors-changed",
G_CALLBACK (on_monitors_changed), native, 0);
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
priv->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
priv->gbm = gbm_create_device (priv->drm_fd);
}
#endif
}
struct gbm_device *
meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
return priv->gbm;
}
void
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
{
update_hw_cursor (native, TRUE);
}

View File

@ -1,55 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_CURSOR_RENDERER_NATIVE_H
#define META_CURSOR_RENDERER_NATIVE_H
#include "meta-cursor-renderer.h"
#define META_TYPE_CURSOR_RENDERER_NATIVE (meta_cursor_renderer_native_get_type ())
#define META_CURSOR_RENDERER_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_RENDERER_NATIVE, MetaCursorRendererNative))
#define META_CURSOR_RENDERER_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_RENDERER_NATIVE, MetaCursorRendererNativeClass))
#define META_IS_CURSOR_RENDERER_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_RENDERER_NATIVE))
#define META_IS_CURSOR_RENDERER_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_RENDERER_NATIVE))
#define META_CURSOR_RENDERER_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_RENDERER_NATIVE, MetaCursorRendererNativeClass))
typedef struct _MetaCursorRendererNative MetaCursorRendererNative;
typedef struct _MetaCursorRendererNativeClass MetaCursorRendererNativeClass;
struct _MetaCursorRendererNative
{
MetaCursorRenderer parent;
};
struct _MetaCursorRendererNativeClass
{
MetaCursorRendererClass parent_class;
};
GType meta_cursor_renderer_native_get_type (void) G_GNUC_CONST;
struct gbm_device * meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *renderer);
void meta_cursor_renderer_native_force_update (MetaCursorRendererNative *renderer);
#endif /* META_CURSOR_RENDERER_NATIVE_H */

View File

@ -0,0 +1,443 @@
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cogl/cogl.h>
#include <cogl/cogl-wayland-server.h>
#include <clutter/clutter.h>
#include <gbm.h>
#include "display-private.h"
#include "meta-cursor-tracker-native.h"
#include "meta-cursor-tracker-private.h"
#include "meta-monitor-manager.h"
#include "meta-cursor-private.h"
#include "wayland/meta-wayland-private.h"
struct _MetaCursorTrackerNative
{
MetaCursorTracker parent;
gboolean has_hw_cursor;
int current_x, current_y;
MetaRectangle current_rect;
MetaRectangle previous_rect;
gboolean previous_is_valid;
CoglPipeline *pipeline;
int drm_fd;
struct gbm_device *gbm;
};
struct _MetaCursorTrackerNativeClass
{
MetaCursorTrackerClass parent_class;
};
G_DEFINE_TYPE (MetaCursorTrackerNative, meta_cursor_tracker_native, META_TYPE_CURSOR_TRACKER);
static void
meta_cursor_tracker_native_load_cursor_pixels (MetaCursorTracker *tracker,
MetaCursorReference *cursor,
uint8_t *pixels,
int width,
int height,
int rowstride,
uint32_t format)
{
MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (tracker);
if (!self->gbm)
return;
meta_cursor_reference_load_gbm_buffer (cursor,
self->gbm,
pixels,
width, height, rowstride,
format);
}
static void
meta_cursor_tracker_native_load_cursor_buffer (MetaCursorTracker *tracker,
MetaCursorReference *cursor,
struct wl_resource *buffer)
{
struct wl_shm_buffer *shm_buffer;
int width, height;
width = cogl_texture_get_width (COGL_TEXTURE (cursor->image.texture));
height = cogl_texture_get_height (COGL_TEXTURE (cursor->image.texture));
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
uint32_t gbm_format;
uint8_t *pixels = wl_shm_buffer_get_data (shm_buffer);
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#else
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#endif
default:
g_warn_if_reached ();
gbm_format = GBM_FORMAT_ARGB8888;
}
meta_cursor_tracker_native_load_cursor_pixels (tracker,
cursor,
pixels,
width,
height,
rowstride,
gbm_format);
}
else
{
MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (tracker);
if (!self->gbm)
return;
meta_cursor_reference_import_gbm_buffer (cursor, self->gbm, buffer, width, height);
}
}
static void
set_crtc_has_hw_cursor (MetaCursorTrackerNative *self,
MetaCRTC *crtc,
gboolean has)
{
MetaCursorTracker *tracker = META_CURSOR_TRACKER (self);
if (has)
{
MetaCursorReference *displayed_cursor = tracker->displayed_cursor;
struct gbm_bo *bo;
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
bo = meta_cursor_reference_get_gbm_bo (displayed_cursor, &hot_x, &hot_y);
handle = gbm_bo_get_handle (bo);
width = gbm_bo_get_width (bo);
height = gbm_bo_get_height (bo);
drmModeSetCursor2 (self->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
crtc->has_hw_cursor = TRUE;
}
else
{
drmModeSetCursor2 (self->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
crtc->has_hw_cursor = FALSE;
}
}
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaCursorTrackerNative *self)
{
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
if (!self->has_hw_cursor)
return;
/* Go through the new list of monitors, find out where the cursor is */
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
for (i = 0; i < n_crtcs; i++)
{
MetaRectangle *rect = &crtcs[i].rect;
gboolean has;
has = meta_rectangle_overlap (&self->current_rect, rect);
/* Need to do it unconditionally here, our tracking is
wrong because we reloaded the CRTCs */
set_crtc_has_hw_cursor (self, &crtcs[i], has);
}
}
static gboolean
should_have_hw_cursor (MetaCursorTrackerNative *self)
{
MetaCursorTracker *tracker = META_CURSOR_TRACKER (self);
if (tracker->displayed_cursor)
return (meta_cursor_reference_get_gbm_bo (tracker->displayed_cursor, NULL, NULL) != NULL);
else
return FALSE;
}
static void
update_hw_cursor (MetaCursorTrackerNative *self)
{
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
gboolean enabled;
enabled = should_have_hw_cursor (self);
self->has_hw_cursor = enabled;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
for (i = 0; i < n_crtcs; i++)
{
MetaRectangle *rect = &crtcs[i].rect;
gboolean has;
has = enabled && meta_rectangle_overlap (&self->current_rect, rect);
if (has || crtcs[i].has_hw_cursor)
set_crtc_has_hw_cursor (self, &crtcs[i], has);
}
}
static void
move_hw_cursor (MetaCursorTrackerNative *self)
{
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
g_assert (self->has_hw_cursor);
for (i = 0; i < n_crtcs; i++)
{
MetaRectangle *rect = &crtcs[i].rect;
gboolean has;
has = meta_rectangle_overlap (&self->current_rect, rect);
if (has != crtcs[i].has_hw_cursor)
set_crtc_has_hw_cursor (self, &crtcs[i], has);
if (has)
drmModeMoveCursor (self->drm_fd, crtcs[i].crtc_id,
self->current_rect.x - rect->x,
self->current_rect.y - rect->y);
}
}
static void
queue_redraw (MetaCursorTrackerNative *self)
{
MetaCursorTracker *tracker = META_CURSOR_TRACKER (self);
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
ClutterActor *stage = compositor->stage;
cairo_rectangle_int_t clip;
/* Clear the location the cursor was at before, if we need to. */
if (self->previous_is_valid)
{
clip.x = self->previous_rect.x;
clip.y = self->previous_rect.y;
clip.width = self->previous_rect.width;
clip.height = self->previous_rect.height;
clutter_actor_queue_redraw_with_clip (stage, &clip);
self->previous_is_valid = FALSE;
}
if (self->has_hw_cursor || !tracker->displayed_cursor)
return;
clip.x = self->current_rect.x;
clip.y = self->current_rect.y;
clip.width = self->current_rect.width;
clip.height = self->current_rect.height;
clutter_actor_queue_redraw_with_clip (stage, &clip);
}
static void
meta_cursor_tracker_native_sync_cursor (MetaCursorTracker *tracker)
{
MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (tracker);
MetaCursorReference *displayed_cursor;
displayed_cursor = tracker->displayed_cursor;
if (displayed_cursor)
{
CoglTexture *texture;
int hot_x, hot_y;
texture = meta_cursor_reference_get_cogl_texture (displayed_cursor, &hot_x, &hot_y);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
self->current_rect.x = self->current_x - hot_x;
self->current_rect.y = self->current_y - hot_y;
self->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
self->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
}
else
{
cogl_pipeline_set_layer_texture (self->pipeline, 0, NULL);
self->current_rect.x = 0;
self->current_rect.y = 0;
self->current_rect.width = 0;
self->current_rect.height = 0;
}
update_hw_cursor (self);
if (self->has_hw_cursor)
move_hw_cursor (self);
else
queue_redraw (self);
}
static void
meta_cursor_tracker_native_get_pointer (MetaCursorTracker *tracker,
int *x,
int *y,
ClutterModifierType *mods)
{
ClutterDeviceManager *cmanager;
ClutterInputDevice *cdevice;
ClutterPoint point;
/* On wayland we can't use GDK, because that only sees the events we
* forward to xwayland.
*/
cmanager = clutter_device_manager_get_default ();
cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE);
clutter_input_device_get_coords (cdevice, NULL, &point);
if (x)
*x = point.x;
if (y)
*y = point.y;
if (mods)
*mods = clutter_input_device_get_modifier_state (cdevice);
}
static void
meta_cursor_tracker_native_finalize (GObject *object)
{
MetaCursorTrackerNative *self = META_CURSOR_TRACKER_NATIVE (object);
if (self->pipeline)
cogl_object_unref (self->pipeline);
if (self->gbm)
gbm_device_destroy (self->gbm);
G_OBJECT_CLASS (meta_cursor_tracker_native_parent_class)->finalize (object);
}
static void
meta_cursor_tracker_native_class_init (MetaCursorTrackerNativeClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaCursorTrackerClass *cursor_tracker_class = META_CURSOR_TRACKER_CLASS (klass);
object_class->finalize = meta_cursor_tracker_native_finalize;
cursor_tracker_class->get_pointer = meta_cursor_tracker_native_get_pointer;
cursor_tracker_class->sync_cursor = meta_cursor_tracker_native_sync_cursor;
cursor_tracker_class->load_cursor_pixels = meta_cursor_tracker_native_load_cursor_pixels;
cursor_tracker_class->load_cursor_buffer = meta_cursor_tracker_native_load_cursor_buffer;
}
static void
meta_cursor_tracker_native_init (MetaCursorTrackerNative *self)
{
MetaWaylandCompositor *compositor;
CoglContext *ctx;
MetaMonitorManager *monitors;
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 = META_CURSOR_TRACKER (self);
meta_cursor_tracker_native_update_position (self,
wl_fixed_to_int (compositor->seat->pointer.x),
wl_fixed_to_int (compositor->seat->pointer.y));
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (ctx));
self->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
self->gbm = gbm_create_device (self->drm_fd);
}
#endif
monitors = meta_monitor_manager_get ();
g_signal_connect_object (monitors, "monitors-changed",
G_CALLBACK (on_monitors_changed), self, 0);
}
void
meta_cursor_tracker_native_update_position (MetaCursorTrackerNative *self,
int new_x,
int new_y)
{
self->current_x = new_x;
self->current_y = new_y;
_meta_cursor_tracker_sync_cursor (META_CURSOR_TRACKER (self));
}
void
meta_cursor_tracker_native_paint (MetaCursorTrackerNative *self)
{
MetaCursorTracker *tracker = META_CURSOR_TRACKER (self);
if (self->has_hw_cursor || !tracker->displayed_cursor)
return;
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
self->pipeline,
self->current_rect.x,
self->current_rect.y,
self->current_rect.x +
self->current_rect.width,
self->current_rect.y +
self->current_rect.height);
self->previous_rect = self->current_rect;
self->previous_is_valid = TRUE;
}
void
meta_cursor_tracker_native_force_update (MetaCursorTrackerNative *self)
{
_meta_cursor_tracker_sync_cursor (META_CURSOR_TRACKER (self));
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_CURSOR_TRACKER_NATIVE_H
#define META_CURSOR_TRACKER_NATIVE_H
#include <glib-object.h>
#include <meta/meta-cursor-tracker.h>
#define META_TYPE_CURSOR_TRACKER_NATIVE (meta_cursor_tracker_native_get_type ())
#define META_CURSOR_TRACKER_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER_NATIVE, MetaCursorTrackerNative))
#define META_CURSOR_TRACKER_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER_NATIVE, MetaCursorTrackerNativeClass))
#define META_IS_CURSOR_TRACKER_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER_NATIVE))
#define META_IS_CURSOR_TRACKER_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER_NATIVE))
#define META_CURSOR_TRACKER_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER_NATIVE, MetaCursorTrackerNativeClass))
typedef struct _MetaCursorTrackerNative MetaCursorTrackerNative;
typedef struct _MetaCursorTrackerNativeClass MetaCursorTrackerNativeClass;
GType meta_cursor_tracker_native_get_type (void);
void meta_cursor_tracker_native_update_position (MetaCursorTrackerNative *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_native_paint (MetaCursorTrackerNative *tracker);
void meta_cursor_tracker_native_force_update (MetaCursorTrackerNative *tracker);
#endif /* META_CURSOR_TRACKER_NATIVE_H */

View File

@ -1,368 +0,0 @@
/*
* 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.
*/
#include "config.h"
#include "meta-launcher.h"
#include <gio/gunixfdlist.h>
#include <clutter/clutter.h>
#include <clutter/egl/clutter-egl.h>
#include <clutter/evdev/clutter-evdev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <systemd/sd-login.h>
#include "dbus-utils.h"
#include "meta-dbus-login1.h"
#include "wayland/meta-wayland-private.h"
#include "backends/meta-backend.h"
#include "meta-cursor-renderer-native.h"
struct _MetaLauncher
{
Login1Session *session_proxy;
Login1Seat *seat_proxy;
gboolean session_active;
};
static Login1Session *
get_session_proxy (GCancellable *cancellable)
{
char *proxy_path;
char *session_id;
Login1Session *session_proxy;
if (sd_pid_get_session (getpid (), &session_id) < 0)
return NULL;
proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
"org.freedesktop.login1",
proxy_path,
cancellable, NULL);
free (proxy_path);
return session_proxy;
}
static Login1Seat *
get_seat_proxy (GCancellable *cancellable)
{
return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
"org.freedesktop.login1",
"/org/freedesktop/login1/seat/self",
cancellable, NULL);
}
static void
session_unpause (void)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
cogl_kms_display_queue_modes_reset (cogl_display);
clutter_evdev_reclaim_devices ();
clutter_egl_thaw_master_clock ();
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaBackend *backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (backend);
/* When we mode-switch back, we need to immediately queue a redraw
* in case nothing else queued one for us, and force the cursor to
* update. */
clutter_actor_queue_redraw (compositor->stage);
meta_cursor_renderer_native_force_update (META_CURSOR_RENDERER_NATIVE (renderer));
}
}
static void
session_pause (void)
{
clutter_evdev_release_devices ();
clutter_egl_freeze_master_clock ();
}
static gboolean
take_device (Login1Session *session_proxy,
int dev_major,
int dev_minor,
int *out_fd,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GVariant *fd_variant = NULL;
int fd = -1;
GUnixFDList *fd_list;
if (!login1_session_call_take_device_sync (session_proxy,
dev_major,
dev_minor,
NULL,
&fd_variant,
NULL, /* paused */
&fd_list,
cancellable,
error))
goto out;
fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
if (fd == -1)
goto out;
*out_fd = fd;
ret = TRUE;
out:
if (fd_variant)
g_variant_unref (fd_variant);
if (fd_list)
g_object_unref (fd_list);
return ret;
}
static gboolean
get_device_info_from_path (const char *path,
int *out_major,
int *out_minor)
{
gboolean ret = FALSE;
int r;
struct stat st;
r = stat (path, &st);
if (r < 0)
goto out;
if (!S_ISCHR (st.st_mode))
goto out;
*out_major = major (st.st_rdev);
*out_minor = minor (st.st_rdev);
ret = TRUE;
out:
return ret;
}
static gboolean
get_device_info_from_fd (int fd,
int *out_major,
int *out_minor)
{
gboolean ret = FALSE;
int r;
struct stat st;
r = fstat (fd, &st);
if (r < 0)
goto out;
if (!S_ISCHR (st.st_mode))
goto out;
*out_major = major (st.st_rdev);
*out_minor = minor (st.st_rdev);
ret = TRUE;
out:
return ret;
}
static int
on_evdev_device_open (const char *path,
int flags,
gpointer user_data,
GError **error)
{
MetaLauncher *self = user_data;
int fd;
int major, minor;
if (!get_device_info_from_path (path, &major, &minor))
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
"Could not get device info for path %s: %m", path);
return -1;
}
if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
return -1;
return fd;
}
static void
on_evdev_device_close (int fd,
gpointer user_data)
{
MetaLauncher *self = user_data;
int major, minor;
GError *error = NULL;
if (!get_device_info_from_fd (fd, &major, &minor))
{
g_warning ("Could not get device info for fd %d: %m", fd);
return;
}
if (!login1_session_call_release_device_sync (self->session_proxy,
major, minor,
NULL, &error))
{
g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
}
}
static void
sync_active (MetaLauncher *self)
{
gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
if (active == self->session_active)
return;
self->session_active = active;
if (active)
session_unpause ();
else
session_pause ();
}
static void
on_active_changed (Login1Session *session,
GParamSpec *pspec,
gpointer user_data)
{
MetaLauncher *self = user_data;
sync_active (self);
}
static gboolean
get_kms_fd (Login1Session *session_proxy,
int *fd_out)
{
int major, minor;
int fd;
GError *error = NULL;
/* XXX -- use udev to find the DRM master device */
if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
{
g_warning ("Could not stat /dev/dri/card0: %m");
return FALSE;
}
if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
{
g_warning ("Could not open DRM device: %s\n", error->message);
g_error_free (error);
return FALSE;
}
*fd_out = fd;
return TRUE;
}
MetaLauncher *
meta_launcher_new (void)
{
MetaLauncher *self;
Login1Session *session_proxy;
GError *error = NULL;
int kms_fd;
session_proxy = get_session_proxy (NULL);
if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
{
g_warning ("Could not take control: %s", error->message);
g_error_free (error);
return NULL;
}
if (!get_kms_fd (session_proxy, &kms_fd))
return NULL;
self = g_slice_new0 (MetaLauncher);
self->session_proxy = session_proxy;
self->seat_proxy = get_seat_proxy (NULL);
self->session_active = TRUE;
clutter_egl_set_kms_fd (kms_fd);
clutter_evdev_set_device_callbacks (on_evdev_device_open,
on_evdev_device_close,
self);
g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
return self;
}
void
meta_launcher_free (MetaLauncher *self)
{
g_object_unref (self->seat_proxy);
g_object_unref (self->session_proxy);
g_slice_free (MetaLauncher, self);
}
gboolean
meta_launcher_activate_session (MetaLauncher *launcher,
GError **error)
{
if (!login1_session_call_activate_sync (launcher->session_proxy, NULL, error))
return FALSE;
sync_active (launcher);
return TRUE;
}
gboolean
meta_launcher_activate_vt (MetaLauncher *launcher,
signed char vt,
GError **error)
{
return login1_seat_call_switch_to_sync (launcher->seat_proxy, vt, NULL, error);
}

View File

@ -1,8 +1,8 @@
/* -*- 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
@ -12,7 +12,7 @@
* 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

View File

@ -0,0 +1,412 @@
/*
* 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.
*/
#include <config.h>
#include <gio/gio.h>
#include <gio/gunixfdmessage.h>
#include <clutter/clutter.h>
#include <clutter/egl/clutter-egl.h>
#include <clutter/evdev/clutter-evdev.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "wayland/meta-wayland-private.h"
#include "meta-cursor-tracker-private.h"
#include "meta-cursor-tracker-native.h"
#include "meta-weston-launch.h"
struct _MetaLauncher
{
GSocket *weston_launch;
gboolean vt_switched;
GMainContext *nested_context;
GMainLoop *nested_loop;
GSource *inner_source;
GSource *outer_source;
};
static void handle_request_vt_switch (MetaLauncher *self);
static gboolean
request_vt_switch_idle (gpointer user_data)
{
handle_request_vt_switch (user_data);
return FALSE;
}
static gboolean
send_message_to_wl (MetaLauncher *self,
void *message,
gsize size,
GSocketControlMessage *out_cmsg,
GSocketControlMessage **in_cmsg,
GError **error)
{
struct weston_launcher_reply reply;
GInputVector in_iov = { &reply, sizeof (reply) };
GOutputVector out_iov = { message, size };
GSocketControlMessage *out_all_cmsg[2];
GSocketControlMessage **in_all_cmsg;
int flags = 0;
int i;
out_all_cmsg[0] = out_cmsg;
out_all_cmsg[1] = NULL;
if (g_socket_send_message (self->weston_launch, NULL,
&out_iov, 1,
out_all_cmsg, -1,
flags, NULL, error) != (gssize)size)
return FALSE;
if (g_socket_receive_message (self->weston_launch, NULL,
&in_iov, 1,
&in_all_cmsg, NULL,
&flags, NULL, error) != sizeof (reply))
return FALSE;
while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
{
/* There were events queued */
g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT);
/* This can never happen, because the only time mutter-launch can queue
this event is after confirming a VT switch, and we don't make requests
during that time.
Note that getting this event would be really bad, because we would be
in the wrong loop/context.
*/
g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER);
switch (reply.header.opcode)
{
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
g_idle_add (request_vt_switch_idle, self);
break;
default:
g_assert_not_reached ();
}
if (g_socket_receive_message (self->weston_launch, NULL,
&in_iov, 1,
NULL, NULL,
&flags, NULL, error) != sizeof (reply))
return FALSE;
}
if (reply.ret != 0)
{
if (reply.ret == -1)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Got failure from weston-launch");
else
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret),
"Got failure from weston-launch: %s", strerror (-reply.ret));
for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
g_object_unref (in_all_cmsg[i]);
g_free (in_all_cmsg);
return FALSE;
}
if (in_all_cmsg && in_all_cmsg[0])
{
for (i = 1; in_all_cmsg[i]; i++)
g_object_unref (in_all_cmsg[i]);
*in_cmsg = in_all_cmsg[0];
}
g_free (in_all_cmsg);
return TRUE;
}
static int
meta_launcher_open_device (MetaLauncher *self,
const char *name,
int flags,
GError **error)
{
struct weston_launcher_open *message;
GSocketControlMessage *cmsg;
gboolean ok;
gsize size;
int *fds, n_fd;
int ret;
size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
message = g_malloc (size);
message->header.opcode = WESTON_LAUNCHER_OPEN;
message->flags = flags;
strcpy (message->path, name);
message->path[strlen(name)] = 0;
ok = send_message_to_wl (self, message, size, NULL, &cmsg, error);
if (ok)
{
g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
g_assert (n_fd == 1);
ret = fds[0];
g_free (fds);
g_object_unref (cmsg);
}
else
ret = -1;
g_free (message);
return ret;
}
static void
meta_launcher_enter (MetaLauncher *launcher)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
cogl_kms_display_queue_modes_reset (cogl_display);
clutter_evdev_reclaim_devices ();
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
/* When we mode-switch back, we need to immediately queue a redraw
* in case nothing else queued one for us, and force the cursor to
* update. */
clutter_actor_queue_redraw (compositor->stage);
meta_cursor_tracker_native_force_update (META_CURSOR_TRACKER_NATIVE (compositor->seat->cursor_tracker));
}
}
static void
meta_launcher_leave (MetaLauncher *launcher)
{
clutter_evdev_release_devices ();
}
static int
on_evdev_device_open (const char *path,
int flags,
gpointer user_data,
GError **error)
{
MetaLauncher *launcher = user_data;
return meta_launcher_open_device (launcher, path, flags, error);
}
static void
on_evdev_device_close (int fd,
gpointer user_data)
{
close (fd);
}
static void
handle_vt_enter (MetaLauncher *launcher)
{
g_assert (launcher->vt_switched);
g_main_loop_quit (launcher->nested_loop);
}
static void
handle_request_vt_switch (MetaLauncher *launcher)
{
struct weston_launcher_message message;
GError *error;
gboolean ok;
meta_launcher_leave (launcher);
message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
error = NULL;
ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error);
if (!ok) {
g_warning ("Failed to acknowledge VT switch: %s", error->message);
g_error_free (error);
return;
}
g_assert (!launcher->vt_switched);
launcher->vt_switched = TRUE;
/* We can't do anything at this point, because we don't
have input devices and we don't have the DRM master,
so let's run a nested busy loop until the VT is reentered */
g_main_loop_run (launcher->nested_loop);
g_assert (launcher->vt_switched);
launcher->vt_switched = FALSE;
meta_launcher_enter (launcher);
}
static gboolean
on_socket_readable (GSocket *socket,
GIOCondition condition,
gpointer user_data)
{
MetaLauncher *launcher = user_data;
struct weston_launcher_event event;
gssize read;
GError *error;
if ((condition & G_IO_IN) == 0)
return TRUE;
error = NULL;
read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
if (read < (gssize)sizeof(event))
{
g_warning ("Error reading from weston-launcher socket: %s", error->message);
g_error_free (error);
return TRUE;
}
switch (event.header.opcode)
{
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
handle_request_vt_switch (launcher);
break;
case WESTON_LAUNCHER_SERVER_VT_ENTER:
handle_vt_enter (launcher);
break;
}
return TRUE;
}
static int
env_get_fd (const char *env)
{
const char *value;
value = g_getenv (env);
if (value == NULL)
return -1;
else
return g_ascii_strtoll (value, NULL, 10);
}
MetaLauncher *
meta_launcher_new (void)
{
MetaLauncher *self = g_slice_new0 (MetaLauncher);
int launch_fd;
launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
if (launch_fd < 0)
g_error ("Invalid mutter-launch socket");
self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
self->nested_context = g_main_context_new ();
self->nested_loop = g_main_loop_new (self->nested_context, FALSE);
self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL);
g_source_attach (self->outer_source, NULL);
g_source_unref (self->outer_source);
self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL);
g_source_attach (self->inner_source, self->nested_context);
g_source_unref (self->inner_source);
clutter_evdev_set_device_callbacks (on_evdev_device_open,
on_evdev_device_close,
self);
#if defined(CLUTTER_WINDOWING_EGL)
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
{
GError *error = NULL;
int fd = meta_launcher_open_device (self, "/dev/dri/card0", O_RDWR, &error);
if (error)
g_error ("Failed to open /dev/dri/card0: %s", error->message);
clutter_egl_set_kms_fd (fd);
}
#endif
return self;
}
void
meta_launcher_free (MetaLauncher *launcher)
{
g_source_destroy (launcher->outer_source);
g_source_destroy (launcher->inner_source);
g_main_loop_unref (launcher->nested_loop);
g_main_context_unref (launcher->nested_context);
g_object_unref (launcher->weston_launch);
g_slice_free (MetaLauncher, launcher);
}
gboolean
meta_launcher_activate_vt (MetaLauncher *launcher,
signed char vt,
GError **error)
{
struct weston_launcher_activate_vt message;
message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
message.vt = vt;
return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
}

View File

@ -17,21 +17,18 @@
* 02111-1307, USA.
*/
#ifndef META_LAUNCHER_H
#define META_LAUNCHER_H
#ifndef META_WESTON_LAUNCH_H
#define META_WESTON_LAUNCH_H
#include <glib-object.h>
#include "weston-launch.h"
typedef struct _MetaLauncher MetaLauncher;
MetaLauncher *meta_launcher_new (void);
void meta_launcher_free (MetaLauncher *self);
gboolean meta_launcher_activate_session (MetaLauncher *self,
GError **error);
gboolean meta_launcher_activate_vt (MetaLauncher *self,
signed char vt,
GError **error);
#endif /* META_LAUNCHER_H */
#endif

View File

@ -0,0 +1,711 @@
/*
* Copyright © 2012 Benjamin Franzke
*
* 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <error.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <termios.h>
#include <linux/vt.h>
#include <linux/major.h>
#include <linux/kd.h>
#include <pwd.h>
#include <grp.h>
#include <xf86drm.h>
#include <systemd/sd-login.h>
#include "weston-launch.h"
#define MAX_ARGV_SIZE 256
#define DRM_MAJOR 226
enum vt_state {
VT_HAS_VT,
VT_PENDING_CONFIRM,
VT_NOT_HAVE_VT,
};
struct weston_launch {
int tty;
int ttynr;
int sock[2];
struct passwd *pw;
int signalfd;
pid_t child;
int verbose;
struct termios terminal_attributes;
int kb_mode;
enum vt_state vt_state;
unsigned vt;
int drm_fd;
};
union cmsg_data { unsigned char b[4]; int fd; };
static void quit (struct weston_launch *wl, int status);
static int
weston_launch_allowed(struct weston_launch *wl)
{
char *session, *seat;
int err;
if (getuid() == 0)
return 1;
err = sd_pid_get_session(getpid(), &session);
if (err == 0 && session) {
if (sd_session_is_active(session) &&
sd_session_get_seat(session, &seat) == 0) {
free(seat);
free(session);
return 1;
}
free(session);
}
return 0;
}
static int
setup_launcher_socket(struct weston_launch *wl)
{
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
error(1, errno, "socketpair failed");
fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
return 0;
}
static int
setup_signals(struct weston_launch *wl)
{
int ret;
sigset_t mask;
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
ret = sigaction(SIGCHLD, &sa, NULL);
assert(ret == 0);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigaction(SIGHUP, &sa, NULL);
ret = sigemptyset(&mask);
assert(ret == 0);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1);
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
assert(ret == 0);
wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (wl->signalfd < 0)
return -errno;
return 0;
}
static void
setenv_fd(const char *env, int fd)
{
char buf[32];
snprintf(buf, sizeof buf, "%d", fd);
setenv(env, buf, 1);
}
static int
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
reply.ret = -1;
if (wl->vt_state != VT_PENDING_CONFIRM) {
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
goto out;
}
if (wl->drm_fd != -1) {
int ret;
ret = drmDropMaster(wl->drm_fd);
if (ret < 0) {
fprintf(stderr, "failed to drop DRM master: %m\n");
} else if (wl->verbose) {
fprintf(stderr, "dropped DRM master for VT switch\n");
}
}
wl->vt_state = VT_NOT_HAVE_VT;
ioctl(wl->tty, VT_RELDISP, 1);
if (wl->verbose)
fprintf(stderr, "mutter-launcher: confirmed VT switch\n");
reply.ret = 0;
out:
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
return 0;
}
static int
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
struct weston_launcher_activate_vt *message;
unsigned vt;
reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
reply.ret = -1;
if (len != sizeof(*message)) {
error(0, 0, "missing value in activate_vt request");
goto out;
}
message = msg->msg_iov->iov_base;
/* Negative values mean that we're activating our own VT */
if (message->vt > 0)
vt = message->vt;
else
vt = wl->vt;
reply.ret = ioctl(wl->tty, VT_ACTIVATE, vt);
if (reply.ret < 0)
reply.ret = -errno;
if (wl->verbose)
fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret);
out:
do {
len = send(wl->sock[0], &reply, sizeof reply, 0);
} while (len < 0 && errno == EINTR);
if (len < 0)
return -1;
return 0;
}
static int
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
struct weston_launcher_reply reply;
int fd = -1;
char control[CMSG_SPACE(sizeof(fd))];
struct cmsghdr *cmsg;
struct stat s;
struct msghdr nmsg;
struct iovec iov;
struct weston_launcher_open *message;
union cmsg_data *data;
int dev_major;
reply.header.opcode = WESTON_LAUNCHER_OPEN;
reply.ret = -1;
message = msg->msg_iov->iov_base;
if ((size_t)len < sizeof(*message))
goto err0;
/* Ensure path is null-terminated */
((char *) message)[len-1] = '\0';
if (stat(message->path, &s) < 0) {
reply.ret = -errno;
goto err0;
}
dev_major = major(s.st_rdev);
if (dev_major != INPUT_MAJOR &&
dev_major != DRM_MAJOR) {
fprintf(stderr, "Device %s is not an input or DRM device\n",
message->path);
reply.ret = -EPERM;
goto err0;
}
if (dev_major == DRM_MAJOR && wl->drm_fd != -1) {
fprintf(stderr, "Already have a DRM device open\n");
reply.ret = -EPERM;
goto err0;
}
fd = open(message->path, message->flags);
if (fd < 0) {
fprintf(stderr, "Error opening device %s: %m\n",
message->path);
reply.ret = -errno;
goto err0;
}
if (dev_major == DRM_MAJOR) {
wl->drm_fd = fd;
}
err0:
memset(&nmsg, 0, sizeof nmsg);
nmsg.msg_iov = &iov;
nmsg.msg_iovlen = 1;
if (fd != -1) {
nmsg.msg_control = control;
nmsg.msg_controllen = sizeof control;
cmsg = CMSG_FIRSTHDR(&nmsg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
data = (union cmsg_data *) CMSG_DATA(cmsg);
data->fd = fd;
nmsg.msg_controllen = cmsg->cmsg_len;
reply.ret = 0;
}
iov.iov_base = &reply;
iov.iov_len = sizeof reply;
if (wl->verbose)
fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n",
message->path, reply.ret, fd);
do {
len = sendmsg(wl->sock[0], &nmsg, 0);
} while (len < 0 && errno == EINTR);
close(fd);
if (len < 0)
return -1;
return 0;
}
static int
handle_socket_msg(struct weston_launch *wl)
{
char control[CMSG_SPACE(sizeof(int))];
char buf[BUFSIZ];
struct msghdr msg;
struct iovec iov;
int ret = -1;
ssize_t len;
struct weston_launcher_message *message;
memset(&msg, 0, sizeof(msg));
iov.iov_base = buf;
iov.iov_len = sizeof buf;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof control;
do {
len = recvmsg(wl->sock[0], &msg, 0);
} while (len < 0 && errno == EINTR);
if (len < 1)
return -1;
message = (void *) buf;
switch (message->opcode) {
case WESTON_LAUNCHER_OPEN:
ret = handle_open(wl, &msg, len);
break;
case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
ret = handle_confirm_vt_switch(wl, &msg, len);
break;
case WESTON_LAUNCHER_ACTIVATE_VT:
ret = handle_activate_vt(wl, &msg, len);
break;
}
return ret;
}
static void
tty_reset(struct weston_launch *wl)
{
struct vt_mode mode = { 0 };
if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
fprintf(stderr, "failed to restore keyboard mode: %m\n");
if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
fprintf(stderr, "could not restore terminal to canonical mode\n");
mode.mode = VT_AUTO;
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
fprintf(stderr, "could not reset vt handling\n");
}
static void
quit(struct weston_launch *wl, int status)
{
if (wl->child > 0)
kill(wl->child, SIGKILL);
close(wl->signalfd);
close(wl->sock[0]);
if (wl->drm_fd > 0)
close(wl->drm_fd);
tty_reset(wl);
exit(status);
}
static int
handle_vt_switch(struct weston_launch *wl)
{
struct weston_launcher_event message;
ssize_t len;
if (wl->vt_state == VT_HAS_VT) {
wl->vt_state = VT_PENDING_CONFIRM;
message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
} else if (wl->vt_state == VT_NOT_HAVE_VT) {
wl->vt_state = VT_HAS_VT;
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
if (wl->drm_fd != -1) {
int ret;
ret = drmSetMaster(wl->drm_fd);
if (ret < 0) {
fprintf(stderr, "failed to become DRM master: %m\n");
/* This is very, very bad, and the compositor will crash soon,
but oh well... */
} else if (wl->verbose) {
fprintf(stderr, "became DRM master after VT switch\n");
}
}
message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
} else
return -1;
message.detail = 0;
do {
len = send(wl->sock[0], &message, sizeof(message), 0);
} while (len < 0 && errno == EINTR);
return 0;
}
static int
handle_signal(struct weston_launch *wl)
{
struct signalfd_siginfo sig;
int pid, status, ret;
if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
error(0, errno, "reading signalfd failed");
return -1;
}
switch (sig.ssi_signo) {
case SIGCHLD:
pid = waitpid(-1, &status, 0);
if (pid == wl->child) {
wl->child = 0;
if (WIFEXITED(status))
ret = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
/*
* If weston dies because of signal N, we
* return 10+N. This is distinct from
* weston-launch dying because of a signal
* (128+N).
*/
ret = 10 + WTERMSIG(status);
else
ret = 0;
quit(wl, ret);
}
break;
case SIGTERM:
case SIGINT:
if (wl->child)
kill(wl->child, sig.ssi_signo);
break;
case SIGUSR1:
return handle_vt_switch(wl);
default:
return -1;
}
return 0;
}
static int
setup_tty(struct weston_launch *wl)
{
struct stat buf;
struct termios raw_attributes;
struct vt_mode mode = { 0 };
char *session;
char path[PATH_MAX];
int ok;
ok = sd_pid_get_session(getpid(), &session);
if (ok < 0)
error(1, -ok, "could not determine current session");
ok = sd_session_get_vt(session, &wl->vt);
if (ok < 0)
error(1, -ok, "could not determine current TTY");
snprintf(path, PATH_MAX, "/dev/tty%u", wl->vt);
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
if (wl->tty < 0)
error(1, errno, "failed to open tty");
if (fstat(wl->tty, &buf) < 0)
error(1, errno, "stat %s failed", path);
if (major(buf.st_rdev) != TTY_MAJOR)
error(1, 0, "invalid tty device: %s", path);
wl->ttynr = minor(buf.st_rdev);
if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
error(1, errno, "could not get terminal attributes");
/* Ignore control characters and disable echo */
raw_attributes = wl->terminal_attributes;
cfmakeraw(&raw_attributes);
/* Fix up line endings to be normal (cfmakeraw hoses them) */
raw_attributes.c_oflag |= OPOST | OCRNL;
/* Don't generate ttou signals */
raw_attributes.c_oflag &= ~TOSTOP;
if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
error(1, errno, "could not put terminal into raw mode");
ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
ok = ioctl(wl->tty, KDSKBMODE, K_OFF);
if (ok < 0) {
ok = ioctl(wl->tty, KDSKBMODE, K_RAW);
if (ok < 0)
error(1, errno, "failed to set keyboard mode on tty");
}
ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
if (ok < 0)
error(1, errno, "failed to set KD_GRAPHICS mode on tty");
wl->vt_state = VT_HAS_VT;
mode.mode = VT_PROCESS;
mode.relsig = SIGUSR1;
mode.acqsig = SIGUSR1;
ok = ioctl(wl->tty, VT_SETMODE, &mode);
if (ok < 0)
error(1, errno, "failed to take control of vt handling");
return 0;
}
static void
drop_privileges(struct weston_launch *wl)
{
if (setgid(wl->pw->pw_gid) < 0 ||
#ifdef HAVE_INITGROUPS
initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
#endif
setuid(wl->pw->pw_uid) < 0)
error(1, errno, "dropping privileges failed");
}
static void
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
{
char command[PATH_MAX];
char *child_argv[MAX_ARGV_SIZE];
sigset_t mask;
int i;
if (wl->verbose)
printf("weston-launch: spawned weston with pid: %d\n", getpid());
drop_privileges(wl);
setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
setenv("LD_LIBRARY_PATH", LIBDIR, 1);
unsetenv("DISPLAY");
/* Do not give our signal mask to the new process. */
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
child_argv[0] = wl->pw->pw_shell;
child_argv[1] = "-l";
child_argv[2] = "-c";
child_argv[3] = command;
for (i = 0; i < argc; ++i)
child_argv[4 + i] = argv[i];
child_argv[4 + i] = NULL;
execv(child_argv[0], child_argv);
error(1, errno, "exec failed");
}
static void
help(const char *name)
{
fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
fprintf(stderr, " -u, --user Start session as specified username\n");
fprintf(stderr, " -v, --verbose Be verbose\n");
fprintf(stderr, " -h, --help Display this help message\n");
}
int
main(int argc, char *argv[])
{
struct weston_launch wl;
int i, c;
struct option opts[] = {
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
};
memset(&wl, 0, sizeof wl);
wl.drm_fd = -1;
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
switch (c) {
case 'v':
wl.verbose = 1;
break;
case 'h':
help("mutter-launch");
exit(EXIT_FAILURE);
}
}
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
error(1, E2BIG, "Too many arguments to pass to weston");
if (optind >= argc)
error(1, 0, "Expected program argument");
wl.pw = getpwuid(getuid());
if (wl.pw == NULL)
error(1, errno, "failed to get username");
if (!weston_launch_allowed(&wl))
error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
if (setup_tty(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_launcher_socket(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_signals(&wl) < 0)
exit(EXIT_FAILURE);
wl.child = fork();
if (wl.child == -1) {
error(1, errno, "fork failed");
exit(EXIT_FAILURE);
}
if (wl.child == 0)
launch_compositor(&wl, argc - optind, argv + optind);
close(wl.sock[1]);
while (1) {
struct pollfd fds[2];
int n;
fds[0].fd = wl.sock[0];
fds[0].events = POLLIN;
fds[1].fd = wl.signalfd;
fds[1].events = POLLIN;
n = poll(fds, 2, -1);
if (n < 0)
error(0, errno, "poll failed");
if (fds[0].revents & POLLIN)
handle_socket_msg(&wl);
if (fds[1].revents)
handle_signal(&wl);
}
return 0;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright © 2012 Benjamin Franzke
* 2013 Red Hat, Inc.
*
* 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 _WESTON_LAUNCH_H_
#define _WESTON_LAUNCH_H_
enum weston_launcher_message_type {
WESTON_LAUNCHER_REQUEST,
WESTON_LAUNCHER_EVENT,
};
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_ACTIVATE_VT = (2 << 1 | WESTON_LAUNCHER_REQUEST),
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (3 << 1 | WESTON_LAUNCHER_REQUEST),
};
enum weston_launcher_server_opcode {
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT),
WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT),
};
struct weston_launcher_message {
int opcode;
};
struct weston_launcher_open {
struct weston_launcher_message header;
int flags;
char path[0];
};
struct weston_launcher_activate_vt {
struct weston_launcher_message header;
signed char vt;
};
struct weston_launcher_reply {
struct weston_launcher_message header;
int ret;
};
struct weston_launcher_event {
struct weston_launcher_message header;
int detail; /* unused, but makes sure replies and events are serialized the same */
};
#endif

View File

@ -1,406 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-backend-x11.h"
#include <clutter/x11/clutter-x11.h>
#include <X11/extensions/sync.h>
#include "meta-idle-monitor-xsync.h"
#include "meta-monitor-manager-xrandr.h"
#include "backends/meta-monitor-manager-dummy.h"
#include "meta-cursor-renderer-x11.h"
#include <meta/util.h>
#include "display-private.h"
#include "compositor/compositor-private.h"
struct _MetaBackendX11Private
{
/* The host X11 display */
Display *xdisplay;
GSource *source;
int xsync_event_base;
int xsync_error_base;
int xinput_opcode;
int xinput_event_base;
int xinput_error_base;
};
typedef struct _MetaBackendX11Private MetaBackendX11Private;
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11, meta_backend_x11, META_TYPE_BACKEND);
static void
handle_alarm_notify (MetaBackend *backend,
XEvent *event)
{
int i;
for (i = 0; i <= backend->device_id_max; i++)
if (backend->device_monitors[i])
meta_idle_monitor_xsync_handle_xevent (backend->device_monitors[i], (XSyncAlarmNotifyEvent*) event);
}
static void
translate_device_event (MetaBackendX11 *x11,
XIDeviceEvent *device_event)
{
Window stage_window = meta_backend_x11_get_xwindow (x11);
if (device_event->event != stage_window)
{
/* This codepath should only ever trigger as an X11 compositor,
* and never under nested, as under nested all backend events
* should be reported with respect to the stage window. */
g_assert (!meta_is_wayland_compositor ());
device_event->event = stage_window;
/* As an X11 compositor, the stage window is always at 0,0, so
* using root coordinates will give us correct stage coordinates
* as well... */
device_event->event_x = device_event->root_x;
device_event->event_y = device_event->root_y;
}
}
/* Clutter makes the assumption that there is only one X window
* per stage, which is a valid assumption to make for a generic
* application toolkit. As such, it will ignore any events sent
* to the a stage that isn't its X window.
*
* When running as an X window manager, we need to respond to
* events from lots of windows. Trick Clutter into translating
* these events by pretending we got an event on the stage window.
*/
static void
maybe_spoof_event_as_stage_event (MetaBackendX11 *x11,
XEvent *event)
{
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
if (event->type == GenericEvent &&
event->xcookie.extension == priv->xinput_opcode)
{
XIEvent *input_event = (XIEvent *) event->xcookie.data;
switch (input_event->evtype)
{
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
translate_device_event (x11, (XIDeviceEvent *) input_event);
break;
default:
break;
}
}
}
static void
handle_host_xevent (MetaBackend *backend,
XEvent *event)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
gboolean bypass_clutter = FALSE;
XGetEventData (priv->xdisplay, &event->xcookie);
if (event->type == (priv->xsync_event_base + XSyncAlarmNotify))
handle_alarm_notify (backend, event);
{
MetaMonitorManager *manager = meta_backend_get_monitor_manager (backend);
if (META_IS_MONITOR_MANAGER_XRANDR (manager) &&
meta_monitor_manager_xrandr_handle_xevent (META_MONITOR_MANAGER_XRANDR (manager), event))
{
bypass_clutter = TRUE;
goto out;
}
}
maybe_spoof_event_as_stage_event (x11, event);
out:
if (!bypass_clutter)
clutter_x11_handle_event (event);
XFreeEventData (priv->xdisplay, &event->xcookie);
}
typedef struct {
GSource base;
GPollFD event_poll_fd;
MetaBackend *backend;
} XEventSource;
static gboolean
x_event_source_prepare (GSource *source,
int *timeout)
{
XEventSource *x_source = (XEventSource *) source;
MetaBackend *backend = x_source->backend;
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
*timeout = -1;
return XPending (priv->xdisplay);
}
static gboolean
x_event_source_check (GSource *source)
{
XEventSource *x_source = (XEventSource *) source;
MetaBackend *backend = x_source->backend;
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
return XPending (priv->xdisplay);
}
static gboolean
x_event_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
XEventSource *x_source = (XEventSource *) source;
MetaBackend *backend = x_source->backend;
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
while (XPending (priv->xdisplay))
{
XEvent event;
XNextEvent (priv->xdisplay, &event);
handle_host_xevent (backend, &event);
}
return TRUE;
}
static GSourceFuncs x_event_funcs = {
x_event_source_prepare,
x_event_source_check,
x_event_source_dispatch,
};
static GSource *
x_event_source_new (MetaBackend *backend)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
GSource *source;
XEventSource *x_source;
source = g_source_new (&x_event_funcs, sizeof (XEventSource));
x_source = (XEventSource *) source;
x_source->backend = backend;
x_source->event_poll_fd.fd = ConnectionNumber (priv->xdisplay);
x_source->event_poll_fd.events = G_IO_IN;
g_source_add_poll (source, &x_source->event_poll_fd);
g_source_attach (source, NULL);
return source;
}
static void
meta_backend_x11_post_init (MetaBackend *backend)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
int major, minor;
priv->xdisplay = clutter_x11_get_default_display ();
priv->source = x_event_source_new (backend);
if (!XSyncQueryExtension (priv->xdisplay, &priv->xsync_event_base, &priv->xsync_error_base) ||
!XSyncInitialize (priv->xdisplay, &major, &minor))
meta_fatal ("Could not initialize XSync");
{
int major = 2, minor = 3;
gboolean has_xi = FALSE;
if (XQueryExtension (priv->xdisplay,
"XInputExtension",
&priv->xinput_opcode,
&priv->xinput_error_base,
&priv->xinput_event_base))
{
if (XIQueryVersion (priv->xdisplay, &major, &minor) == Success)
{
int version = (major * 10) + minor;
if (version >= 22)
has_xi = TRUE;
}
}
if (!has_xi)
meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n");
}
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
}
static MetaIdleMonitor *
meta_backend_x11_create_idle_monitor (MetaBackend *backend,
int device_id)
{
return g_object_new (META_TYPE_IDLE_MONITOR_XSYNC,
"device-id", device_id,
NULL);
}
static MetaMonitorManager *
meta_backend_x11_create_monitor_manager (MetaBackend *backend)
{
/* If we're a Wayland compositor using the X11 backend,
* we're a nested configuration, so return the dummy
* monitor setup. */
if (meta_is_wayland_compositor ())
return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL);
return g_object_new (META_TYPE_MONITOR_MANAGER_XRANDR, NULL);
}
static MetaCursorRenderer *
meta_backend_x11_create_cursor_renderer (MetaBackend *backend)
{
return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL);
}
static gboolean
meta_backend_x11_grab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
int ret;
XISetMask (mask.mask, XI_ButtonPress);
XISetMask (mask.mask, XI_ButtonRelease);
XISetMask (mask.mask, XI_Enter);
XISetMask (mask.mask, XI_Leave);
XISetMask (mask.mask, XI_Motion);
XISetMask (mask.mask, XI_KeyPress);
XISetMask (mask.mask, XI_KeyRelease);
ret = XIGrabDevice (priv->xdisplay, device_id,
meta_backend_x11_get_xwindow (x11),
timestamp,
None,
XIGrabModeAsync, XIGrabModeAsync,
False, /* owner_events */
&mask);
return (ret == Success);
}
static gboolean
meta_backend_x11_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
int ret;
ret = XIUngrabDevice (priv->xdisplay, device_id, timestamp);
return (ret == Success);
}
static void
meta_backend_x11_warp_pointer (MetaBackend *backend,
int x,
int y)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
XIWarpPointer (priv->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
None,
meta_backend_x11_get_xwindow (x11),
0, 0, 0, 0,
x, y);
}
static void
meta_backend_x11_class_init (MetaBackendX11Class *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
backend_class->post_init = meta_backend_x11_post_init;
backend_class->create_idle_monitor = meta_backend_x11_create_idle_monitor;
backend_class->create_monitor_manager = meta_backend_x11_create_monitor_manager;
backend_class->create_cursor_renderer = meta_backend_x11_create_cursor_renderer;
backend_class->grab_device = meta_backend_x11_grab_device;
backend_class->ungrab_device = meta_backend_x11_ungrab_device;
backend_class->warp_pointer = meta_backend_x11_warp_pointer;
}
static void
meta_backend_x11_init (MetaBackendX11 *x11)
{
/* We do X11 event retrieval ourselves */
clutter_x11_disable_event_retrieval ();
}
Display *
meta_backend_x11_get_xdisplay (MetaBackendX11 *x11)
{
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
return priv->xdisplay;
}
Window
meta_backend_x11_get_xwindow (MetaBackendX11 *x11)
{
MetaDisplay *display = meta_get_display ();
MetaCompositor *compositor = display->compositor;
if (compositor == NULL)
return None;
ClutterStage *stage = CLUTTER_STAGE (compositor->stage);
return clutter_x11_get_stage_window (stage);
}

View File

@ -1,58 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_BACKEND_X11_H
#define META_BACKEND_X11_H
#include "backends/meta-backend-private.h"
#include <X11/Xlib.h>
#define META_TYPE_BACKEND_X11 (meta_backend_x11_get_type ())
#define META_BACKEND_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKEND_X11, MetaBackendX11))
#define META_BACKEND_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKEND_X11, MetaBackendX11Class))
#define META_IS_BACKEND_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKEND_X11))
#define META_IS_BACKEND_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKEND_X11))
#define META_BACKEND_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKEND_X11, MetaBackendX11Class))
typedef struct _MetaBackendX11 MetaBackendX11;
typedef struct _MetaBackendX11Class MetaBackendX11Class;
struct _MetaBackendX11
{
MetaBackend parent;
};
struct _MetaBackendX11Class
{
MetaBackendClass parent_class;
};
GType meta_backend_x11_get_type (void) G_GNUC_CONST;
Display * meta_backend_x11_get_xdisplay (MetaBackendX11 *backend);
Window meta_backend_x11_get_xwindow (MetaBackendX11 *backend);
#endif /* META_BACKEND_X11_H */

View File

@ -1,99 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include "config.h"
#include "meta-cursor-renderer-x11.h"
#include "meta-backend-x11.h"
#include "meta-stage.h"
struct _MetaCursorRendererX11Private
{
gboolean server_cursor_visible;
};
typedef struct _MetaCursorRendererX11Private MetaCursorRendererX11Private;
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererX11, meta_cursor_renderer_x11, META_TYPE_CURSOR_RENDERER);
static gboolean
meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererX11 *x11 = META_CURSOR_RENDERER_X11 (renderer);
MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11);
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
Window xwindow = meta_backend_x11_get_xwindow (backend);
if (xwindow == None)
return FALSE;
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
MetaCursorReference *cursor_ref = meta_cursor_renderer_get_cursor (renderer);
gboolean has_server_cursor = FALSE;
if (cursor_ref)
{
MetaCursor cursor = meta_cursor_reference_get_meta_cursor (cursor_ref);
if (cursor != META_CURSOR_NONE)
{
Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor);
XDefineCursor (xdisplay, xwindow, xcursor);
XFlush (xdisplay);
XFreeCursor (xdisplay, xcursor);
has_server_cursor = TRUE;
}
}
if (has_server_cursor != priv->server_cursor_visible)
{
if (has_server_cursor)
XFixesShowCursor (xdisplay, xwindow);
else
XFixesHideCursor (xdisplay, xwindow);
priv->server_cursor_visible = has_server_cursor;
}
return priv->server_cursor_visible;
}
static void
meta_cursor_renderer_x11_class_init (MetaCursorRendererX11Class *klass)
{
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_CLASS (klass);
renderer_class->update_cursor = meta_cursor_renderer_x11_update_cursor;
}
static void
meta_cursor_renderer_x11_init (MetaCursorRendererX11 *x11)
{
MetaCursorRendererX11Private *priv = meta_cursor_renderer_x11_get_instance_private (x11);
/* XFixes has no way to retrieve the current cursor visibility. */
priv->server_cursor_visible = TRUE;
}

View File

@ -1,52 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_CURSOR_RENDERER_X11_H
#define META_CURSOR_RENDERER_X11_H
#include "meta-cursor-renderer.h"
#define META_TYPE_CURSOR_RENDERER_X11 (meta_cursor_renderer_x11_get_type ())
#define META_CURSOR_RENDERER_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_RENDERER_X11, MetaCursorRendererX11))
#define META_CURSOR_RENDERER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_RENDERER_X11, MetaCursorRendererX11Class))
#define META_IS_CURSOR_RENDERER_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_RENDERER_X11))
#define META_IS_CURSOR_RENDERER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_RENDERER_X11))
#define META_CURSOR_RENDERER_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_RENDERER_X11, MetaCursorRendererX11Class))
typedef struct _MetaCursorRendererX11 MetaCursorRendererX11;
typedef struct _MetaCursorRendererX11Class MetaCursorRendererX11Class;
struct _MetaCursorRendererX11
{
MetaCursorRenderer parent;
};
struct _MetaCursorRendererX11Class
{
MetaCursorRendererClass parent_class;
};
GType meta_cursor_renderer_x11_get_type (void) G_GNUC_CONST;
#endif /* META_CURSOR_RENDERER_X11_H */

View File

@ -0,0 +1,138 @@
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk/gdkx.h>
#include <meta/errors.h>
#include "display-private.h"
#include "meta-cursor-tracker-x11.h"
#include "meta-cursor-tracker-private.h"
#include "meta-cursor-private.h"
struct _MetaCursorTrackerX11
{
MetaCursorTracker parent;
};
struct _MetaCursorTrackerX11Class
{
MetaCursorTrackerClass parent_class;
};
G_DEFINE_TYPE (MetaCursorTrackerX11, meta_cursor_tracker_x11, META_TYPE_CURSOR_TRACKER);
static void
meta_cursor_tracker_x11_get_pointer (MetaCursorTracker *tracker,
int *x,
int *y,
ClutterModifierType *mods)
{
GdkDeviceManager *gmanager;
GdkDevice *gdevice;
GdkScreen *gscreen;
/* We can't use the clutter interface when not running as a wayland
* compositor, because we need to query the server, rather than
* using the last cached value.
*/
gmanager = gdk_display_get_device_manager (gdk_display_get_default ());
gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);
gdk_device_get_position (gdevice, &gscreen, x, y);
if (mods)
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
}
static void
meta_cursor_tracker_x11_sync_cursor (MetaCursorTracker *tracker)
{
MetaDisplay *display = meta_get_display ();
meta_error_trap_push (display);
if (tracker->is_showing)
XFixesShowCursor (display->xdisplay,
DefaultRootWindow (display->xdisplay));
else
XFixesHideCursor (display->xdisplay,
DefaultRootWindow (display->xdisplay));
meta_error_trap_pop (display);
}
static void
meta_cursor_tracker_x11_ensure_cursor (MetaCursorTracker *tracker)
{
MetaDisplay *display = meta_get_display ();
XFixesCursorImage *cursor_image;
MetaCursorReference *cursor;
if (tracker->has_window_cursor)
return;
cursor_image = XFixesGetCursorImage (display->xdisplay);
if (!cursor_image)
return;
cursor = meta_cursor_reference_from_xfixes_cursor_image (cursor_image);
_meta_cursor_tracker_set_window_cursor (tracker, TRUE, cursor);
XFree (cursor_image);
}
static void
meta_cursor_tracker_x11_class_init (MetaCursorTrackerX11Class *klass)
{
MetaCursorTrackerClass *cursor_tracker_class = META_CURSOR_TRACKER_CLASS (klass);
cursor_tracker_class->get_pointer = meta_cursor_tracker_x11_get_pointer;
cursor_tracker_class->sync_cursor = meta_cursor_tracker_x11_sync_cursor;
cursor_tracker_class->ensure_cursor = meta_cursor_tracker_x11_ensure_cursor;
}
static void
meta_cursor_tracker_x11_init (MetaCursorTrackerX11 *self)
{
MetaDisplay *display = meta_get_display ();
XFixesSelectCursorInput (display->xdisplay,
DefaultRootWindow (display->xdisplay),
XFixesDisplayCursorNotifyMask);
}
gboolean
meta_cursor_tracker_x11_handle_xevent (MetaCursorTrackerX11 *tracker,
XEvent *xevent)
{
MetaDisplay *display = meta_get_display ();
XFixesCursorNotifyEvent *notify_event;
if (xevent->xany.type != display->xfixes_event_base + XFixesCursorNotify)
return FALSE;
notify_event = (XFixesCursorNotifyEvent *)xevent;
if (notify_event->subtype != XFixesDisplayCursorNotify)
return FALSE;
_meta_cursor_tracker_set_window_cursor (META_CURSOR_TRACKER (tracker), FALSE, NULL);
return TRUE;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_CURSOR_TRACKER_X11_H
#define META_CURSOR_TRACKER_X11_H
#include <glib-object.h>
#include <meta/meta-cursor-tracker.h>
#define META_TYPE_CURSOR_TRACKER_X11 (meta_cursor_tracker_x11_get_type ())
#define META_CURSOR_TRACKER_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER_X11, MetaCursorTrackerX11))
#define META_CURSOR_TRACKER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER_X11, MetaCursorTrackerX11Class))
#define META_IS_CURSOR_TRACKER_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER_X11))
#define META_IS_CURSOR_TRACKER_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER_X11))
#define META_CURSOR_TRACKER_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER_X11, MetaCursorTrackerX11Class))
typedef struct _MetaCursorTrackerX11 MetaCursorTrackerX11;
typedef struct _MetaCursorTrackerX11Class MetaCursorTrackerX11Class;
GType meta_cursor_tracker_x11_get_type (void);
gboolean
meta_cursor_tracker_x11_handle_xevent (MetaCursorTrackerX11 *tracker,
XEvent *xevent);
#endif /* META_CURSOR_TRACKER_X11_H */

View File

@ -25,7 +25,8 @@
#include "meta-idle-monitor-xsync.h"
#include "meta-idle-monitor-private.h"
#include "meta-backend-x11.h"
#include <meta/util.h>
#include "display-private.h"
#include <string.h>
@ -190,9 +191,10 @@ static void
meta_idle_monitor_xsync_constructed (GObject *object)
{
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
monitor_xsync->display = meta_backend_x11_get_xdisplay (backend);
g_assert (!meta_is_wayland_compositor ());
monitor_xsync->display = meta_get_display ()->xdisplay;
init_xsync (monitor_xsync);
G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->constructed (object);
@ -289,10 +291,7 @@ meta_idle_monitor_xsync_make_watch (MetaIdleMonitor *monitor,
g_hash_table_add (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm);
if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec)
{
watch->idle_source_id = g_idle_add (fire_watch_idle, watch);
g_source_set_name_by_id (watch->idle_source_id, "[mutter] fire_watch_idle");
}
watch->idle_source_id = g_idle_add (fire_watch_idle, watch);
}
else
{

View File

@ -44,4 +44,6 @@ GType meta_idle_monitor_xsync_get_type (void);
void meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor,
XSyncAlarmNotifyEvent *xevent);
void meta_idle_monitor_xsync_handle_xevent_all (XEvent *xevent);
#endif /* META_IDLE_MONITOR_XSYNC_H */

View File

@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
@ -8,7 +8,7 @@
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -18,7 +18,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
@ -36,7 +36,6 @@
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/dpms.h>
#include "meta-backend-x11.h"
#include <meta/main.h>
#include <meta/errors.h>
#include "edid.h"
@ -142,16 +141,16 @@ static gboolean
output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
MetaDisplay *display = meta_get_display ();
gboolean value;
Atom atom, actual_type;
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
atom = XInternAtom (manager_xrandr->xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->output_id,
atom,
display->atom__MUTTER_PRESENTATION_OUTPUT,
0, G_MAXLONG, False, False, XA_CARDINAL,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
@ -178,16 +177,16 @@ static int
output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
MetaDisplay *display = meta_get_display ();
gboolean value;
Atom atom, actual_type;
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *buffer;
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
XRRGetOutputProperty (manager_xrandr->xdisplay,
(XID)output->output_id,
atom,
display->atom_BACKLIGHT,
0, G_MAXLONG, False, False, XA_INTEGER,
&actual_type, &actual_format,
&nitems, &bytes_after, &buffer);
@ -206,13 +205,14 @@ static void
output_get_backlight_limits_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output)
{
Atom atom;
MetaDisplay *display = meta_get_display ();
XRRPropertyInfo *info;
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
meta_error_trap_push (display);
info = XRRQueryOutputProperty (manager_xrandr->xdisplay,
(XID)output->output_id,
atom);
display->atom_BACKLIGHT);
meta_error_trap_pop (display);
if (info == NULL)
{
@ -272,7 +272,7 @@ get_edid_property (Display *dpy,
}
XFree (prop);
return result;
}
@ -314,13 +314,14 @@ static gboolean
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
XID output_id)
{
Atom atom;
MetaDisplay *display = meta_get_display ();
XRRPropertyInfo *info;
gboolean result = FALSE;
atom = XInternAtom (manager_xrandr->xdisplay, "hotplug_mode_update", False);
meta_error_trap_push (display);
info = XRRQueryOutputProperty (manager_xrandr->xdisplay, output_id,
atom);
display->atom_hotplug_mode_update);
meta_error_trap_pop (display);
if (info)
{
@ -349,7 +350,9 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
XRRFreeScreenResources (manager_xrandr->resources);
manager_xrandr->resources = NULL;
meta_error_trap_push (meta_get_display ());
dpms_capable = DPMSCapable (manager_xrandr->xdisplay);
meta_error_trap_pop (meta_get_display ());
if (dpms_capable &&
DPMSInfo (manager_xrandr->xdisplay, &dpms_state, &dpms_enabled) &&
@ -449,8 +452,10 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
XRRFreeCrtcInfo (crtc);
}
meta_error_trap_push (meta_get_display ());
primary_output = XRRGetOutputPrimary (manager_xrandr->xdisplay,
DefaultRootWindow (manager_xrandr->xdisplay));
meta_error_trap_pop (meta_get_display ());
n_actual_outputs = 0;
for (i = 0; i < (unsigned)resources->noutput; i++)
@ -632,8 +637,10 @@ meta_monitor_manager_xrandr_set_power_save_mode (MetaMonitorManager *manager,
return;
}
meta_error_trap_push (meta_get_display ());
DPMSForceLevel (manager_xrandr->xdisplay, state);
DPMSSetTimeouts (manager_xrandr->xdisplay, 0, 0, 0);
meta_error_trap_pop (meta_get_display ());
}
static Rotation
@ -667,13 +674,12 @@ output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
MetaOutput *output,
gboolean presentation)
{
Atom atom;
MetaDisplay *display = meta_get_display ();
int value = presentation;
atom = XInternAtom (manager_xrandr->xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
XRRChangeOutputProperty (manager_xrandr->xdisplay,
(XID)output->output_id,
atom,
display->atom__MUTTER_PRESENTATION_OUTPUT,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char*) &value, 1);
}
@ -686,10 +692,11 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
unsigned int n_outputs)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
MetaDisplay *display = meta_get_display ();
unsigned i;
int width, height, width_mm, height_mm;
XGrabServer (manager_xrandr->xdisplay);
meta_display_grab (display);
/* First compute the new size of the screen (framebuffer) */
width = 0; height = 0;
@ -783,8 +790,10 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
*/
width_mm = (width / DPI_FALLBACK) * 25.4 + 0.5;
height_mm = (height / DPI_FALLBACK) * 25.4 + 0.5;
meta_error_trap_push (display);
XRRSetScreenSize (manager_xrandr->xdisplay, DefaultRootWindow (manager_xrandr->xdisplay),
width, height, width_mm, height_mm);
meta_error_trap_pop (display);
for (i = 0; i < n_crtcs; i++)
{
@ -841,6 +850,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
goto next;
}
meta_error_trap_push (display);
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
@ -849,6 +859,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
(XID)mode->mode_id,
wl_transform_to_xrandr (crtc_info->transform),
outputs, n_outputs);
meta_error_trap_pop (display);
if (ok != Success)
{
@ -889,9 +900,11 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
if (output_info->is_primary)
{
meta_error_trap_push (display);
XRRSetOutputPrimary (manager_xrandr->xdisplay,
DefaultRootWindow (manager_xrandr->xdisplay),
(XID)output_info->output->output_id);
meta_error_trap_pop (display);
}
output_set_presentation_xrandr (manager_xrandr,
@ -917,8 +930,7 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
output->is_primary = FALSE;
}
XUngrabServer (manager_xrandr->xdisplay);
XFlush (manager_xrandr->xdisplay);
meta_display_ungrab (display);
}
static void
@ -927,17 +939,18 @@ meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager,
gint value)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
Atom atom;
MetaDisplay *display = meta_get_display ();
int hw_value;
hw_value = round ((double)value / 100.0 * output->backlight_max + output->backlight_min);
atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
meta_error_trap_push (display);
XRRChangeOutputProperty (manager_xrandr->xdisplay,
(XID)output->output_id,
atom,
display->atom_BACKLIGHT,
XA_INTEGER, 32, PropModeReplace,
(unsigned char *) &hw_value, 1);
meta_error_trap_pop (display);
/* We're not selecting for property notifies, so update the value immediately */
output->backlight = normalize_backlight (output, hw_value);
@ -995,65 +1008,11 @@ meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
meta_monitor_manager_rebuild_derived (manager);
}
static void
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
static gboolean
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
XEvent *event)
{
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
manager_xrandr->xdisplay = meta_backend_x11_get_xdisplay (backend);
if (!XRRQueryExtension (manager_xrandr->xdisplay,
&manager_xrandr->rr_event_base,
&manager_xrandr->rr_error_base))
{
return;
}
else
{
/* We only use ScreenChangeNotify, but GDK uses the others,
and we don't want to step on its toes */
XRRSelectInput (manager_xrandr->xdisplay,
DefaultRootWindow (manager_xrandr->xdisplay),
RRScreenChangeNotifyMask
| RRCrtcChangeNotifyMask
| RROutputPropertyNotifyMask);
}
}
static void
meta_monitor_manager_xrandr_finalize (GObject *object)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object);
if (manager_xrandr->resources)
XRRFreeScreenResources (manager_xrandr->resources);
manager_xrandr->resources = NULL;
G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object);
}
static void
meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
{
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_monitor_manager_xrandr_finalize;
manager_class->read_current = meta_monitor_manager_xrandr_read_current;
manager_class->read_edid = meta_monitor_manager_xrandr_read_edid;
manager_class->apply_configuration = meta_monitor_manager_xrandr_apply_configuration;
manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode;
manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight;
manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma;
manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma;
}
gboolean
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
XEvent *event)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
@ -1114,3 +1073,59 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
return TRUE;
}
static void
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
{
MetaDisplay *display = meta_get_display ();
manager_xrandr->xdisplay = display->xdisplay;
if (!XRRQueryExtension (manager_xrandr->xdisplay,
&manager_xrandr->rr_event_base,
&manager_xrandr->rr_error_base))
{
return;
}
else
{
/* We only use ScreenChangeNotify, but GDK uses the others,
and we don't want to step on its toes */
XRRSelectInput (manager_xrandr->xdisplay,
DefaultRootWindow (manager_xrandr->xdisplay),
RRScreenChangeNotifyMask
| RRCrtcChangeNotifyMask
| RROutputPropertyNotifyMask);
}
}
static void
meta_monitor_manager_xrandr_finalize (GObject *object)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (object);
if (manager_xrandr->resources)
XRRFreeScreenResources (manager_xrandr->resources);
manager_xrandr->resources = NULL;
G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object);
}
static void
meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
{
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_monitor_manager_xrandr_finalize;
manager_class->read_current = meta_monitor_manager_xrandr_read_current;
manager_class->read_edid = meta_monitor_manager_xrandr_read_edid;
manager_class->apply_configuration = meta_monitor_manager_xrandr_apply_configuration;
manager_class->set_power_save_mode = meta_monitor_manager_xrandr_set_power_save_mode;
manager_class->change_backlight = meta_monitor_manager_xrandr_change_backlight;
manager_class->get_crtc_gamma = meta_monitor_manager_xrandr_get_crtc_gamma;
manager_class->set_crtc_gamma = meta_monitor_manager_xrandr_set_crtc_gamma;
manager_class->handle_xevent = meta_monitor_manager_xrandr_handle_xevent;
}

View File

@ -37,7 +37,4 @@ typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
GType meta_monitor_manager_xrandr_get_type (void);
gboolean meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager,
XEvent *event);
#endif /* META_MONITOR_MANAGER_XRANDR_H */

View File

@ -72,7 +72,6 @@
#include <meta/meta-shadow-factory.h>
#include "meta-window-actor-private.h"
#include "meta-window-group.h"
#include "meta-stage.h"
#include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */
#include "util-private.h"
@ -80,9 +79,6 @@
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
#include "backends/meta-backend.h"
#include "backends/x11/meta-backend-x11.h"
#include "wayland/meta-wayland-private.h"
static gboolean
@ -151,13 +147,16 @@ process_damage (MetaCompositor *compositor,
static Window
get_output_window (MetaCompositor *compositor)
{
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
Window output;
MetaDisplay *display = compositor->display;
Display *xdisplay = display->xdisplay;
Window output, xroot;
XWindowAttributes attr;
long event_mask;
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
output = XCompositeGetOverlayWindow (xdisplay, DefaultRootWindow (xdisplay));
xroot = display->screen->xroot;
output = XCompositeGetOverlayWindow (xdisplay, xroot);
meta_core_add_old_event_mask (xdisplay, output, &mask);
@ -172,6 +171,12 @@ get_output_window (MetaCompositor *compositor)
XISetMask (mask.mask, XI_Motion);
XISelectEvents (xdisplay, output, &mask, 1);
event_mask = ExposureMask | PropertyChangeMask;
if (XGetWindowAttributes (xdisplay, output, &attr))
event_mask |= attr.your_event_mask;
XSelectInput (xdisplay, output, event_mask);
return output;
}
@ -322,16 +327,38 @@ meta_stage_is_focused (MetaScreen *screen)
}
static gboolean
grab_devices (MetaModalOptions options,
guint32 timestamp)
begin_modal_x11 (MetaCompositor *compositor,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaBackend *backend = META_BACKEND (meta_get_backend ());
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
MetaDisplay *display = compositor->display;
Display *xdpy = meta_display_get_xdisplay (display);
Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
int result;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
if (!meta_backend_grab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp))
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
XISetMask (mask.mask, XI_ButtonPress);
XISetMask (mask.mask, XI_ButtonRelease);
XISetMask (mask.mask, XI_Enter);
XISetMask (mask.mask, XI_Leave);
XISetMask (mask.mask, XI_Motion);
result = XIGrabDevice (xdpy,
META_VIRTUAL_CORE_POINTER_ID,
grab_window,
timestamp,
None,
XIGrabModeAsync, XIGrabModeAsync,
False, /* owner_events */
&mask);
if (result != Success)
goto fail;
pointer_grabbed = TRUE;
@ -339,7 +366,22 @@ grab_devices (MetaModalOptions options,
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
{
if (!meta_backend_grab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp))
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
XISetMask (mask.mask, XI_KeyPress);
XISetMask (mask.mask, XI_KeyRelease);
result = XIGrabDevice (xdpy,
META_VIRTUAL_CORE_KEYBOARD_ID,
grab_window,
timestamp,
None,
XIGrabModeAsync, XIGrabModeAsync,
False, /* owner_events */
&mask);
if (result != Success)
goto fail;
keyboard_grabbed = TRUE;
@ -349,9 +391,9 @@ grab_devices (MetaModalOptions options,
fail:
if (pointer_grabbed)
meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
if (keyboard_grabbed)
meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
return FALSE;
}
@ -371,14 +413,9 @@ meta_begin_modal_for_plugin (MetaCompositor *compositor,
if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE)
return FALSE;
/* XXX: why is this needed? */
XIUngrabDevice (display->xdisplay,
META_VIRTUAL_CORE_POINTER_ID,
timestamp);
XSync (display->xdisplay, False);
if (!grab_devices (options, timestamp))
return FALSE;
if (!meta_is_wayland_compositor ())
if (!begin_modal_x11 (compositor, plugin, options, timestamp))
return FALSE;
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->grab_window = NULL;
@ -397,7 +434,7 @@ meta_end_modal_for_plugin (MetaCompositor *compositor,
guint32 timestamp)
{
MetaDisplay *display = compositor->display;
MetaBackend *backend = meta_get_backend ();
Display *xdpy = meta_display_get_xdisplay (display);
g_return_if_fail (is_modal (display));
@ -406,11 +443,15 @@ meta_end_modal_for_plugin (MetaCompositor *compositor,
display->grab_have_pointer = FALSE;
display->grab_have_keyboard = FALSE;
meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp);
meta_backend_ungrab_device (backend, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
if (meta_is_wayland_compositor ())
meta_display_sync_wayland_input_focus (display);
{
meta_display_sync_wayland_input_focus (display);
}
else
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
}
}
static void
@ -450,7 +491,7 @@ redirect_windows (MetaScreen *screen)
*/
while (TRUE)
{
meta_error_trap_push (display);
meta_error_trap_push_with_return (display);
XCompositeRedirectSubwindows (xdisplay, xroot, CompositeRedirectManual);
XSync (xdisplay, FALSE);
@ -478,17 +519,16 @@ meta_compositor_manage (MetaCompositor *compositor)
MetaScreen *screen = display->screen;
Window xwin = 0;
gint width, height;
MetaWaylandCompositor *wayland_compositor;
meta_screen_set_cm_selection (display->screen);
/* We will have already created a stage if running as a wayland
* compositor... */
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *wayland_compositor = meta_wayland_compositor_get_default ();
compositor->stage = meta_stage_new ();
clutter_actor_show (compositor->stage);
wayland_compositor->stage = compositor->stage;
wayland_compositor = meta_wayland_compositor_get_default ();
compositor->stage = wayland_compositor->stage;
meta_screen_get_size (screen, &width, &height);
clutter_actor_set_size (compositor->stage, width, height);
@ -505,12 +545,12 @@ meta_compositor_manage (MetaCompositor *compositor)
XResizeWindow (xdisplay, xwin, width, height);
{
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend);
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 (backend_xdisplay, xwin, &mask);
meta_core_add_old_event_mask (xdisplay, xwin, &mask);
XISetMask (mask.mask, XI_KeyPress);
XISetMask (mask.mask, XI_KeyRelease);
@ -524,7 +564,13 @@ meta_compositor_manage (MetaCompositor *compositor)
XIClearMask (mask.mask, XI_TouchBegin);
XIClearMask (mask.mask, XI_TouchEnd);
XIClearMask (mask.mask, XI_TouchUpdate);
XISelectEvents (backend_xdisplay, xwin, &mask, 1);
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);
}
}
@ -555,10 +601,10 @@ meta_compositor_manage (MetaCompositor *compositor)
meta_empty_stage_input_region (screen);
/* Make sure there isn't any left-over output shape on the
/* 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.
@ -708,6 +754,29 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
}
static gboolean
is_grabbed_event (MetaDisplay *display,
XEvent *event)
{
if (event->type == GenericEvent &&
event->xcookie.extension == display->xinput_opcode)
{
XIEvent *xev = (XIEvent *) event->xcookie.data;
switch (xev->evtype)
{
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
return TRUE;
}
}
return FALSE;
}
void
meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window)
@ -744,11 +813,87 @@ meta_compositor_window_surface_changed (MetaCompositor *compositor,
meta_window_actor_update_surface (window_actor);
}
static gboolean
event_is_passive_button_grab (MetaDisplay *display,
XIDeviceEvent *device_event)
{
/* see display.c for which events are passive button
grabs (meta_display_grab_window_buttons() and
meta_display_handle_events())
we need to filter them here because normally they
would be sent to gtk+ (they are on gtk+ frame xwindow),
but we want to redirect them to clutter
*/
if (device_event->evtype != XI_ButtonPress)
return FALSE;
if (display->window_grab_modifiers == 0)
return FALSE;
if ((device_event->mods.effective & display->window_grab_modifiers) !=
display->window_grab_modifiers)
return FALSE;
return device_event->detail < 4;
}
/* Clutter makes the assumption that there is only one X window
* per stage, which is a valid assumption to make for a generic
* application toolkit. As such, it will ignore any events sent
* to the a stage that isn't its X window.
*
* When running as an X window manager, we need to respond to
* events from lots of windows. Trick Clutter into translating
* these events by pretending we got an event on the stage window.
*/
static void
maybe_spoof_event_as_stage_event (MetaCompositor *compositor,
MetaWindow *window,
XEvent *event)
{
MetaDisplay *display = compositor->display;
if (event->type == GenericEvent &&
event->xcookie.extension == display->xinput_opcode)
{
XIEvent *input_event = (XIEvent *) event->xcookie.data;
XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event);
switch (input_event->evtype)
{
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
/* If this is a window frame, and we think GTK+ needs to handle the event,
let GTK+ handle it without mangling */
if (window && window->frame && device_event->event == window->frame->xwindow &&
(meta_grab_op_is_clicking (display->grab_op) ||
(display->grab_op == META_GRAB_OP_NONE && !event_is_passive_button_grab (display, device_event))))
break;
case XI_KeyPress:
case XI_KeyRelease:
/* If this is a GTK+ widget, like a window menu, let GTK+ handle
* it as-is without mangling. */
if (meta_ui_window_is_widget (display->screen->ui, device_event->event))
break;
device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (compositor->stage));
device_event->event_x = device_event->root_x;
device_event->event_y = device_event->root_y;
break;
default:
break;
}
}
}
/**
* meta_compositor_process_event: (skip)
* @compositor:
* @event:
* @window:
* @compositor:
* @event:
* @window:
*
*/
gboolean
@ -756,6 +901,20 @@ meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event,
MetaWindow *window)
{
MetaDisplay *display = compositor->display;
if (is_modal (display) && is_grabbed_event (display, event))
{
meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event);
/* We always consume events even if the plugin says it didn't handle them;
* exclusive is exclusive */
return TRUE;
}
if (!meta_is_wayland_compositor ())
maybe_spoof_event_as_stage_event (compositor, window, event);
if (meta_plugin_manager_xevent_filter (compositor->plugin_mgr, event))
return TRUE;
@ -1356,13 +1515,3 @@ meta_compositor_hide_tile_preview (MetaCompositor *compositor)
{
meta_plugin_manager_hide_tile_preview (compositor->plugin_mgr);
}
void
meta_compositor_show_window_menu (MetaCompositor *compositor,
MetaWindow *window,
MetaWindowMenuType menu,
int x,
int y)
{
meta_plugin_manager_show_window_menu (compositor->plugin_mgr, window, menu, x, y);
}

View File

@ -356,21 +356,3 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
return FALSE;
}
void
meta_plugin_manager_show_window_menu (MetaPluginManager *plugin_mgr,
MetaWindow *window,
MetaWindowMenuType menu,
int x,
int y)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = plugin_mgr->compositor->display;
if (display->display_opening)
return;
if (klass->show_window_menu)
klass->show_window_menu (plugin, window, menu, x, y);
}

View File

@ -80,12 +80,4 @@ gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr,
MetaRectangle *tile_rect,
int tile_monitor_number);
gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr);
void meta_plugin_manager_show_window_menu (MetaPluginManager *mgr,
MetaWindow *window,
MetaWindowMenuType menu,
int x,
int y);
#endif

View File

@ -81,8 +81,18 @@ _meta_plugin_xevent_filter (MetaPlugin *plugin,
{
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
if (klass->xevent_filter)
return klass->xevent_filter (plugin, xev);
/* 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 (klass->xevent_filter && klass->xevent_filter (plugin, xev))
return TRUE;
else if (!meta_is_wayland_compositor ())
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
else
return FALSE;
}

View File

@ -1,176 +0,0 @@
/*
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#include <config.h>
#include "meta-stage.h"
#include "meta-cursor-private.h"
#include "meta-backend.h"
#include <meta/util.h>
struct _MetaStagePrivate {
CoglPipeline *pipeline;
gboolean should_paint_cursor;
MetaCursorReference *cursor;
MetaRectangle current_rect;
MetaRectangle previous_rect;
gboolean previous_is_valid;
};
typedef struct _MetaStagePrivate MetaStagePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaStage, meta_stage, CLUTTER_TYPE_STAGE);
static void
update_pipeline (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
if (priv->cursor)
{
CoglTexture *texture = meta_cursor_reference_get_cogl_texture (priv->cursor, NULL, NULL);
cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
}
else
cogl_pipeline_set_layer_texture (priv->pipeline, 0, NULL);
}
static void
meta_stage_finalize (GObject *object)
{
MetaStage *stage = META_STAGE (object);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
if (priv->pipeline)
cogl_object_unref (priv->pipeline);
}
static void
paint_cursor (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
g_assert (meta_is_wayland_compositor ());
if (!priv->cursor)
return;
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
priv->pipeline,
priv->current_rect.x,
priv->current_rect.y,
priv->current_rect.x +
priv->current_rect.width,
priv->current_rect.y +
priv->current_rect.height);
priv->previous_rect = priv->current_rect;
priv->previous_is_valid = TRUE;
}
static void
meta_stage_paint (ClutterActor *actor)
{
MetaStage *stage = META_STAGE (actor);
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
if (meta_is_wayland_compositor ())
paint_cursor (stage);
}
static void
meta_stage_class_init (MetaStageClass *klass)
{
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
GObjectClass *object_class = (GObjectClass *) klass;
object_class->finalize = meta_stage_finalize;
actor_class->paint = meta_stage_paint;
}
static void
meta_stage_init (MetaStage *stage)
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
priv->pipeline = cogl_pipeline_new (ctx);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
}
ClutterActor *
meta_stage_new (void)
{
return g_object_new (META_TYPE_STAGE,
"cursor-visible", FALSE,
NULL);
}
static void
queue_redraw (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
cairo_rectangle_int_t clip;
/* Clear the location the cursor was at before, if we need to. */
if (priv->previous_is_valid)
{
clip.x = priv->previous_rect.x;
clip.y = priv->previous_rect.y;
clip.width = priv->previous_rect.width;
clip.height = priv->previous_rect.height;
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
priv->previous_is_valid = FALSE;
}
/* And queue a redraw for the current cursor location. */
if (priv->cursor)
{
clip.x = priv->current_rect.x;
clip.y = priv->current_rect.y;
clip.width = priv->current_rect.width;
clip.height = priv->current_rect.height;
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
}
}
void
meta_stage_set_cursor (MetaStage *stage,
MetaCursorReference *cursor,
MetaRectangle *rect)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
if (priv->cursor != cursor)
{
priv->cursor = cursor;
update_pipeline (stage);
}
priv->current_rect = *rect;
queue_redraw (stage);
}

View File

@ -1,59 +0,0 @@
/*
* 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_STAGE_H
#define META_STAGE_H
#include <clutter/clutter.h>
#include "meta-cursor.h"
#include <meta/boxes.h>
G_BEGIN_DECLS
#define META_TYPE_STAGE (meta_stage_get_type ())
#define META_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_STAGE, MetaStage))
#define META_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_STAGE, MetaStageClass))
#define META_IS_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_STAGE))
#define META_IS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_STAGE))
#define META_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_STAGE, MetaStageClass))
typedef struct _MetaStage MetaStage;
typedef struct _MetaStageClass MetaStageClass;
struct _MetaStageClass
{
ClutterStageClass parent_class;
};
struct _MetaStage
{
ClutterStage parent;
};
GType meta_stage_get_type (void) G_GNUC_CONST;
ClutterActor *meta_stage_new (void);
void meta_stage_set_cursor (MetaStage *stage,
MetaCursorReference *cursor,
MetaRectangle *rect);
G_END_DECLS
#endif /* META_STAGE_H */

View File

@ -108,62 +108,6 @@ meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor)
return FALSE;
}
static int
get_output_scale (int output_id)
{
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
MetaOutput *outputs;
guint n_outputs, i;
int output_scale = 1;
outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
for (i = 0; i < n_outputs; i++)
{
if (outputs[i].output_id == output_id)
{
output_scale = outputs[i].scale;
break;
}
}
return output_scale;
}
double
meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *actor)
{
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (actor);
MetaWaylandSurface *surface = priv->surface;
MetaWindow *window = surface->window;
int output_scale = 1;
while (surface)
{
if (surface->window)
{
window = surface->window;
break;
}
surface = surface->sub.parent;
}
/* XXX: We do not handle x11 clients yet */
if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11)
output_scale = get_output_scale (window->monitor->output_id);
return (double)output_scale / (double)priv->surface->scale;
}
void
meta_surface_actor_wayland_scale_texture (MetaSurfaceActorWayland *actor)
{
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (actor));
double output_scale = meta_surface_actor_wayland_get_scale (actor);
clutter_actor_set_scale (CLUTTER_ACTOR (stex), output_scale, output_scale);
}
static MetaWindow *
meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
{
@ -172,42 +116,6 @@ meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
return priv->surface->window;
}
static void
meta_surface_actor_wayland_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
double scale = meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (self));
clutter_actor_get_preferred_width (CLUTTER_ACTOR (stex), for_height, min_width_p, natural_width_p);
if (min_width_p)
*min_width_p *= scale;
if (natural_width_p)
*natural_width_p *= scale;
}
static void
meta_surface_actor_wayland_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
double scale = meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (self));
clutter_actor_get_preferred_height (CLUTTER_ACTOR (stex), for_width, min_height_p, natural_height_p);
if (min_height_p)
*min_height_p *= scale;
if (natural_height_p)
*natural_height_p *= scale;
}
static void
meta_surface_actor_wayland_dispose (GObject *object)
{
@ -222,12 +130,8 @@ static void
meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
{
MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
actor_class->get_preferred_width = meta_surface_actor_wayland_get_preferred_width;
actor_class->get_preferred_height = meta_surface_actor_wayland_get_preferred_height;
surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage;
surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint;
surface_actor_class->is_visible = meta_surface_actor_wayland_is_visible;

View File

@ -61,9 +61,6 @@ MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWay
void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
MetaWaylandBuffer *buffer);
double meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *actor);
void meta_surface_actor_wayland_scale_texture (MetaSurfaceActorWayland *actor);
G_END_DECLS
#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */

View File

@ -60,7 +60,6 @@ struct _MetaTextureTower
CoglTexture *textures[MAX_TEXTURE_LEVELS];
CoglOffscreen *fbos[MAX_TEXTURE_LEVELS];
Box invalid[MAX_TEXTURE_LEVELS];
CoglPipeline *pipeline_template;
};
/**
@ -92,9 +91,6 @@ meta_texture_tower_free (MetaTextureTower *tower)
{
g_return_if_fail (tower != NULL);
if (tower->pipeline_template != NULL)
cogl_object_unref (tower->pipeline_template);
meta_texture_tower_set_base_texture (tower, NULL);
g_slice_free (MetaTextureTower, tower);
@ -377,7 +373,7 @@ texture_tower_create_texture (MetaTextureTower *tower,
tower->invalid[level].y2 = height;
}
static void
static gboolean
texture_tower_revalidate_fbo (MetaTextureTower *tower,
int level)
{
@ -388,50 +384,174 @@ texture_tower_revalidate_fbo (MetaTextureTower *tower,
int dest_texture_width = cogl_texture_get_width (dest_texture);
int dest_texture_height = cogl_texture_get_height (dest_texture);
Box *invalid = &tower->invalid[level];
CoglFramebuffer *fb;
CoglError *catch_error = NULL;
CoglPipeline *pipeline;
CoglMatrix modelview;
if (tower->fbos[level] == NULL)
tower->fbos[level] = cogl_offscreen_new_with_texture (dest_texture);
tower->fbos[level] = cogl_offscreen_new_to_texture (dest_texture);
fb = COGL_FRAMEBUFFER (tower->fbos[level]);
if (tower->fbos[level] == NULL)
return FALSE;
if (!cogl_framebuffer_allocate (fb, &catch_error))
cogl_push_framebuffer (COGL_FRAMEBUFFER (tower->fbos[level]));
cogl_ortho (0, dest_texture_width, dest_texture_height, 0, -1., 1.);
cogl_matrix_init_identity (&modelview);
cogl_set_modelview_matrix (&modelview);
cogl_set_source_texture (tower->textures[level - 1]);
cogl_rectangle_with_texture_coords (invalid->x1, invalid->y1,
invalid->x2, invalid->y2,
(2. * invalid->x1) / source_texture_width,
(2. * invalid->y1) / source_texture_height,
(2. * invalid->x2) / source_texture_width,
(2. * invalid->y2) / source_texture_height);
cogl_pop_framebuffer ();
return TRUE;
}
static void
fill_copy (guchar *buf,
const guchar *source,
int width)
{
memcpy (buf, source, width * 4);
}
static void
fill_scale_down (guchar *buf,
const guchar *source,
int width)
{
while (width > 1)
{
cogl_error_free (catch_error);
return;
buf[0] = (source[0] + source[4]) / 2;
buf[1] = (source[1] + source[5]) / 2;
buf[2] = (source[2] + source[6]) / 2;
buf[3] = (source[3] + source[7]) / 2;
buf += 4;
source += 8;
width -= 2;
}
cogl_framebuffer_orthographic (fb, 0, 0, dest_texture_width, dest_texture_height, -1., 1.);
if (!tower->pipeline_template)
if (width > 0)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
tower->pipeline_template = cogl_pipeline_new (ctx);
cogl_pipeline_set_blend (tower->pipeline_template, "RGBA = ADD (SRC_COLOR, 0)", NULL);
buf[0] = source[0] / 2;
buf[1] = source[1] / 2;
buf[2] = source[2] / 2;
buf[3] = source[3] / 2;
}
}
static void
texture_tower_revalidate_client (MetaTextureTower *tower,
int level)
{
CoglTexture *source_texture = tower->textures[level - 1];
int source_texture_width = cogl_texture_get_width (source_texture);
int source_texture_height = cogl_texture_get_height (source_texture);
guint source_rowstride;
guchar *source_data;
CoglTexture *dest_texture = tower->textures[level];
int dest_texture_width = cogl_texture_get_width (dest_texture);
int dest_texture_height = cogl_texture_get_height (dest_texture);
int dest_x = tower->invalid[level].x1;
int dest_y = tower->invalid[level].y1;
int dest_width = tower->invalid[level].x2 - tower->invalid[level].x1;
int dest_height = tower->invalid[level].y2 - tower->invalid[level].y1;
guchar *dest_data;
guchar *source_tmp1 = NULL, *source_tmp2 = NULL;
int i, j;
source_rowstride = source_texture_width * 4;
source_data = g_malloc (source_texture_height * source_rowstride);
cogl_texture_get_data (source_texture, TEXTURE_FORMAT, source_rowstride,
source_data);
dest_data = g_malloc (dest_height * dest_width * 4);
if (dest_texture_height < source_texture_height)
{
source_tmp1 = g_malloc (dest_width * 4);
source_tmp2 = g_malloc (dest_width * 4);
}
pipeline = cogl_pipeline_copy (tower->pipeline_template);
cogl_pipeline_set_layer_texture (pipeline, 0, tower->textures[level - 1]);
for (i = 0; i < dest_height; i++)
{
guchar *dest_row = dest_data + i * dest_width * 4;
if (dest_texture_height < source_texture_height)
{
guchar *source1, *source2;
guchar *dest;
cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
invalid->x1, invalid->y1,
invalid->x2, invalid->y2,
(2. * invalid->x1) / source_texture_width,
(2. * invalid->y1) / source_texture_height,
(2. * invalid->x2) / source_texture_width,
(2. * invalid->y2) / source_texture_height);
if (dest_texture_width < source_texture_width)
{
fill_scale_down (source_tmp1,
source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
fill_scale_down (source_tmp2,
source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
}
else
{
fill_copy (source_tmp1,
source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 4,
dest_width);
fill_copy (source_tmp2,
source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 4,
dest_width);
}
cogl_object_unref (pipeline);
source1 = source_tmp1;
source2 = source_tmp2;
dest = dest_row;
for (j = 0; j < dest_width * 4; j++)
*(dest++) = (*(source1++) + *(source2++)) / 2;
}
else
{
if (dest_texture_width < source_texture_width)
fill_scale_down (dest_row,
source_data + (i + dest_y) * source_rowstride + dest_x * 2 * 4,
dest_width * 2);
else
fill_copy (dest_row,
source_data + (i + dest_y) * source_rowstride,
dest_width);
}
}
cogl_texture_set_region (dest_texture,
0, 0,
dest_x, dest_y,
dest_width, dest_height,
dest_width, dest_height,
TEXTURE_FORMAT,
4 * dest_width,
dest_data);
if (dest_texture_height < source_texture_height)
{
g_free (source_tmp1);
g_free (source_tmp2);
}
g_free (source_data);
g_free (dest_data);
}
static void
texture_tower_revalidate (MetaTextureTower *tower,
int level)
{
texture_tower_revalidate_fbo (tower, level);
if (!texture_tower_revalidate_fbo (tower, level))
texture_tower_revalidate_client (tower, level);
}
/**

View File

@ -32,7 +32,6 @@
#include "meta-surface-actor.h"
#include "meta-surface-actor-x11.h"
#include "meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-surface.h"
@ -550,16 +549,6 @@ meta_window_actor_get_shape_bounds (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
cairo_region_get_extents (priv->shape_region, bounds);
if (META_IS_SURFACE_ACTOR_WAYLAND (priv->surface))
{
double scale = priv->surface ?
meta_surface_actor_wayland_get_scale (META_SURFACE_ACTOR_WAYLAND (priv->surface)) : 1.;
bounds->x *= scale;
bounds->y *= scale;
bounds->width *= scale;
bounds->height *= scale;
}
}
static void
@ -866,7 +855,6 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
* to be drawn when the timer expires.
*/
priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL);
g_source_set_name_by_id (priv->send_frame_messages_timer, "[mutter] send_frame_messages_timeout");
}
void

View File

@ -34,6 +34,7 @@
#define DESTROY_TIMEOUT 100
#define MINIMIZE_TIMEOUT 250
#define MAXIMIZE_TIMEOUT 250
#define MAP_TIMEOUT 250
#define SWITCH_TIMEOUT 500
@ -76,6 +77,18 @@ static void map (MetaPlugin *plugin,
MetaWindowActor *actor);
static void destroy (MetaPlugin *plugin,
MetaWindowActor *actor);
static void maximize (MetaPlugin *plugin,
MetaWindowActor *actor,
gint x,
gint y,
gint width,
gint height);
static void unmaximize (MetaPlugin *plugin,
MetaWindowActor *actor,
gint x,
gint y,
gint width,
gint height);
static void switch_workspace (MetaPlugin *plugin,
gint from,
@ -122,8 +135,12 @@ typedef struct _ActorPrivate
ClutterActor *orig_parent;
ClutterTimeline *tml_minimize;
ClutterTimeline *tml_maximize;
ClutterTimeline *tml_destroy;
ClutterTimeline *tml_map;
gboolean is_minimized : 1;
gboolean is_maximized : 1;
} ActorPrivate;
/* callback data for when animations complete */
@ -199,6 +216,8 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
plugin_class->start = start;
plugin_class->map = map;
plugin_class->minimize = minimize;
plugin_class->maximize = maximize;
plugin_class->unmaximize = unmaximize;
plugin_class->destroy = destroy;
plugin_class->switch_workspace = switch_workspace;
plugin_class->show_tile_preview = show_tile_preview;
@ -503,6 +522,8 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
apriv->is_minimized = TRUE;
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
MINIMIZE_TIMEOUT,
@ -523,6 +544,115 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
meta_plugin_minimize_completed (plugin, window_actor);
}
/*
* Minimize effect completion callback; this function restores actor state, and
* calls the manager callback function.
*/
static void
on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
/*
* Must reverse the effect of the effect.
*/
MetaPlugin *plugin = data->plugin;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (data->actor);
ActorPrivate *apriv = get_actor_private (window_actor);
apriv->tml_maximize = NULL;
/* FIXME - don't assume the original scale was 1.0 */
clutter_actor_set_scale (data->actor, 1.0, 1.0);
/* Now notify the manager that we are done with this effect */
meta_plugin_maximize_completed (plugin, window_actor);
g_free (data);
}
/*
* The Nature of Maximize operation is such that it is difficult to do a visual
* effect that would work well. Scaling, the obvious effect, does not work that
* well, because at the end of the effect we end up with window content bigger
* and differently laid out than in the real window; this is a proof concept.
*
* (Something like a sound would be more appropriate.)
*/
static void
maximize (MetaPlugin *plugin,
MetaWindowActor *window_actor,
gint end_x, gint end_y, gint end_width, gint end_height)
{
MetaWindowType type;
ClutterActor *actor = CLUTTER_ACTOR (window_actor);
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
type = meta_window_get_window_type (meta_window);
if (type == META_WINDOW_NORMAL)
{
ClutterAnimation *animation;
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
ActorPrivate *apriv = get_actor_private (window_actor);
gfloat width, height;
gfloat x, y;
apriv->is_maximized = TRUE;
clutter_actor_get_size (actor, &width, &height);
clutter_actor_get_position (actor, &x, &y);
/*
* Work out the scale and anchor point so that the window is expanding
* smoothly into the target size.
*/
scale_x = (gdouble)end_width / (gdouble) width;
scale_y = (gdouble)end_height / (gdouble) height;
animation = clutter_actor_animate (actor,
CLUTTER_EASE_IN_SINE,
MAXIMIZE_TIMEOUT,
"scale-x", scale_x,
"scale-y", scale_y,
NULL);
apriv->tml_maximize = clutter_animation_get_timeline (animation);
data->plugin = plugin;
data->actor = actor;
g_signal_connect (apriv->tml_maximize, "completed",
G_CALLBACK (on_maximize_effect_complete),
data);
return;
}
meta_plugin_maximize_completed (plugin, window_actor);
}
/*
* See comments on the maximize() function.
*
* (Just a skeleton code.)
*/
static void
unmaximize (MetaPlugin *plugin,
MetaWindowActor *window_actor,
gint end_x, gint end_y, gint end_width, gint end_height)
{
MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor);
MetaWindowType type = meta_window_get_window_type (meta_window);
if (type == META_WINDOW_NORMAL)
{
ActorPrivate *apriv = get_actor_private (window_actor);
apriv->is_maximized = FALSE;
}
/* Do this conditionally, if the effect requires completion callback. */
meta_plugin_unmaximize_completed (plugin, window_actor);
}
static void
on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
{
@ -578,6 +708,9 @@ map (MetaPlugin *plugin, MetaWindowActor *window_actor)
g_signal_connect (apriv->tml_map, "completed",
G_CALLBACK (on_map_effect_complete),
data);
apriv->is_minimized = FALSE;
}
else
meta_plugin_map_completed (plugin, window_actor);
@ -738,6 +871,12 @@ kill_window_effects (MetaPlugin *plugin,
g_signal_emit_by_name (apriv->tml_minimize, "completed", NULL);
}
if (apriv->tml_maximize)
{
clutter_timeline_stop (apriv->tml_maximize);
g_signal_emit_by_name (apriv->tml_maximize, "completed", NULL);
}
if (apriv->tml_map)
{
clutter_timeline_stop (apriv->tml_map);

View File

@ -121,7 +121,7 @@ meta_region_builder_finish (MetaRegionBuilder *builder)
return result;
}
/* MetaRegionIterator */
@ -171,7 +171,7 @@ meta_region_iterator_next (MetaRegionIterator *iter)
iter->line_end = TRUE;
}
}
static void
add_expanded_rect (MetaRegionBuilder *builder,
int x,

Some files were not shown because too many files have changed in this diff Show More