mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 15:40:41 -05:00
Merge branch 'wayland'
This has one regression: the basic touch support added by
Carlos Garnacho in 991c85f
is now partially reverted, since
we ported to Clutter events for this. We'll need to either
port his changes to Clutter, or restructure event handling
in mutter directly.
This commit is contained in:
commit
912cf8ee5f
27
.gitignore
vendored
27
.gitignore
vendored
@ -23,7 +23,7 @@ src/50-mutter-navigation.xml
|
||||
src/50-mutter-system.xml
|
||||
src/50-mutter-windows.xml
|
||||
src/mutter-wm.desktop
|
||||
src/mutter.desktop
|
||||
src/mutter-wayland.desktop
|
||||
*.o
|
||||
*.a
|
||||
*.lo
|
||||
@ -46,12 +46,13 @@ POTFILES
|
||||
po/*.pot
|
||||
50-metacity-desktop-key.xml
|
||||
50-metacity-key.xml
|
||||
libmutter.pc
|
||||
mutter
|
||||
mutter-theme-viewer
|
||||
mutter.desktop
|
||||
libmutter-wayland.pc
|
||||
mutter-wayland
|
||||
mutter-launch
|
||||
org.gnome.mutter.gschema.valid
|
||||
org.gnome.mutter.gschema.xml
|
||||
org.gnome.mutter.wayland.gschema.valid
|
||||
org.gnome.mutter.wayland.gschema.xml
|
||||
testasyncgetprop
|
||||
testboxes
|
||||
testgradient
|
||||
@ -75,9 +76,15 @@ src/mutter-enum-types.[ch]
|
||||
src/stamp-mutter-enum-types.h
|
||||
src/mutter-marshal.[ch]
|
||||
src/stamp-mutter-marshal.h
|
||||
src/meta-dbus-xrandr.[ch]
|
||||
src/meta-dbus-display-config.[ch]
|
||||
src/meta-dbus-idle-monitor.[ch]
|
||||
src/mutter-plugins.pc
|
||||
src/gtk-shell-protocol.c
|
||||
src/gtk-shell-server-protocol.h
|
||||
src/xdg-shell-protocol.c
|
||||
src/xdg-shell-server-protocol.h
|
||||
src/xserver-protocol.c
|
||||
src/xserver-server-protocol.h
|
||||
doc/reference/*.args
|
||||
doc/reference/*.bak
|
||||
doc/reference/*.hierarchy
|
||||
@ -95,3 +102,11 @@ doc/reference/meta-undocumented.txt
|
||||
doc/reference/meta-unused.txt
|
||||
doc/reference/meta-docs.sgml
|
||||
doc/reference/meta.types
|
||||
gtk-doc.m4
|
||||
intltool.m4
|
||||
libtool.m4
|
||||
ltoptions.m4
|
||||
ltsugar.m4
|
||||
ltversion.m4
|
||||
lt~obsolete.m4
|
||||
.dirstamp
|
||||
|
159
COMPLIANCE
159
COMPLIANCE
@ -1,159 +0,0 @@
|
||||
Metacity Standards Compliance
|
||||
=============================
|
||||
$Id$
|
||||
|
||||
1) Introduction
|
||||
2) EWMH Compliance
|
||||
a. Root Window Properties
|
||||
b. Root Window Messages
|
||||
c. Application Window Properties
|
||||
d. Window Manager Protocols
|
||||
3) ICCCM Compliance
|
||||
|
||||
1) Introduction
|
||||
---------------
|
||||
|
||||
This document details metacity compliance with the relevent standards.
|
||||
The format of this document is as follows:
|
||||
|
||||
[-/+?] Hint Name/Feature Name (Version number)
|
||||
Errata/Comments
|
||||
|
||||
The first character indicates the level of compliance as follows:
|
||||
- none
|
||||
/ partial
|
||||
+ complete
|
||||
? unknown
|
||||
|
||||
The title indicates a feature or a hint in the specification, and the
|
||||
version number indicates the minimum version of the specification
|
||||
supported by metacity. Later versions may be supported if no
|
||||
incompatible changes have been made in the specification.
|
||||
|
||||
2) EWMH Compliance
|
||||
------------------
|
||||
|
||||
The EWMH, or Extended Window Manager Hints is a freedesktop.org-
|
||||
developed standard to support a number of conventions for
|
||||
communication between the window manager and clients. It builds on
|
||||
and extends the ICCCM (See Section 3). A copy of the current EWMH
|
||||
standard is available at http://freedesktop.org/Standards/wm-spec/
|
||||
|
||||
a. Root Window Properties
|
||||
-------------------------
|
||||
|
||||
+ _NET_SUPPORTED (1.3)
|
||||
|
||||
+ _NET_CLIENT_LIST (1.3)
|
||||
|
||||
+ _NET_NUMBER_OF_DESKTOPS (1.3)
|
||||
|
||||
+ _NET_DESKTOP_GEOMETRY (1.3)
|
||||
Metacity does not implement large desktops, so this is kept set to
|
||||
the screen size.
|
||||
|
||||
+ _NET_DESKTOP_VIEWPORT (1.3)
|
||||
Metacity does not implement viewports, so this is a constant (0,0).
|
||||
|
||||
+ _NET_CURRENT_DESKTOP (1.3)
|
||||
|
||||
+ _NET_DESKTOP_NAMES (1.3)
|
||||
|
||||
+ _NET_ACTIVE_WINDOW (1.3)
|
||||
|
||||
+ _NET_WORKAREA (1.3)
|
||||
|
||||
+ _NET_SUPPORTING_WM_CHECK (1.3)
|
||||
|
||||
+ _NET_VIRTUAL_ROOTS (1.3)
|
||||
Metacity does not read or set this property, but it does not use
|
||||
virtual roots to implement virtual desktops, so it complies with the
|
||||
specification.
|
||||
|
||||
+ _NET_DESKTOP_LAYOUT (1.3)
|
||||
|
||||
+ _NET_SHOWING_DESKTOP (1.3)
|
||||
|
||||
b. Root Window Messages
|
||||
-----------------------
|
||||
|
||||
+ _NET_CLOSE_WINDOW (1.3)
|
||||
|
||||
- _NET_MOVERESIZE_WINDOW (1.3)
|
||||
Metacity supports this message, but the specification is unclear on
|
||||
the layout of the detail value, and as such it is #if 0'd in the code
|
||||
|
||||
+ _NET_WM_MOVERESIZE (1.3)
|
||||
|
||||
- _NET_RESTACK_WINDOW (1.3)
|
||||
Metacity will raise or lower windows in response to this message,
|
||||
but the sibling restack modes are not supported, and it is currently
|
||||
#if 0'd in the code.
|
||||
|
||||
+ _NET_REQUEST_FRAME_EXTENTS (1.3)
|
||||
|
||||
c. Application Window Properties
|
||||
--------------------------------
|
||||
|
||||
+ _NET_WM_NAME (1.3)
|
||||
|
||||
+ _NET_WM_VISIBLE_NAME (1.3)
|
||||
Metacity does not set this property, but metacity will never display
|
||||
a name different from _NET_WM_NAME
|
||||
|
||||
+ _NET_WM_ICON_NAME (1.3)
|
||||
|
||||
+ _NET_WM_VISIBLE_ICON_NAME (1.3)
|
||||
Metacity does not set this property, but metacity will never display
|
||||
a name different from _NET_WM_NAME
|
||||
|
||||
+ _NET_WM_DESKTOP (1.3)
|
||||
|
||||
+ _NET_WM_WINDOW_TYPE (1.3)
|
||||
|
||||
/ _NET_WM_STATE (1.3)
|
||||
This property is read and updated according to the specification,
|
||||
but see caveat below.
|
||||
Metacity does not recognize separate vertical and horizontal
|
||||
maximization states. Currently metacity will do a two-dimensional
|
||||
maximization if either property is set.
|
||||
See: http://bugzilla.gnome.org/show_bug.cgi?id=113601
|
||||
Metacity doesn't implement viewports so _NET_WM_STATE_STICKY is
|
||||
unimplemented.
|
||||
|
||||
+ _NET_WM_ALLOWED_ACTIONS (1.3)
|
||||
Metacity keeps this hint up to date. The code is somewhat crufty
|
||||
and should be rewritten, though it is functional.
|
||||
See: http://bugzilla.gnome.org/show_bug.cgi?id=90420
|
||||
|
||||
+ _NET_WM_STRUT (1.3)
|
||||
|
||||
+ _NET_WM_STRUT_PARTIAL (1.3)
|
||||
|
||||
+ _NET_WM_ICON_GEOMETRY (1.3)
|
||||
Metacity uses this property to draw minimize/restore animations
|
||||
|
||||
+ _NET_WM_ICON (1.3)
|
||||
|
||||
+ _NET_WM_PID (1.3)
|
||||
|
||||
+ _NET_WM_HANDLED_ICONS (1.3)
|
||||
Metacity does not read or set this property. However, metacity
|
||||
never manages iconified windows, and so has no need to do so.
|
||||
|
||||
+ _NET_WM_USER_TIME (1.3)
|
||||
Metacity uses this property to prevent applications from stealing
|
||||
focus if supported by the toolkit.
|
||||
|
||||
+ _NET_FRAME_EXTENTS (1.3)
|
||||
If set in response to a _NET_REQUEST_FRAME_EXTENTS message received
|
||||
prior to the window being mapped, this may be an estimate. This is,
|
||||
however, expressly allowed by the specification.
|
||||
|
||||
d. Window Manager Protocols
|
||||
---------------------------
|
||||
+ _NET_WM_PING (1.3)
|
||||
|
||||
3) ICCCM Compliance
|
||||
-------------------
|
||||
TODO
|
298
HACKING
298
HACKING
@ -1,298 +0,0 @@
|
||||
Intro...
|
||||
|
||||
Window managers have a few ways in which they are significantly different
|
||||
from other applications. This file, combined with the code overview in
|
||||
doc/code-overview.txt, should hopefully provide a series of relatively
|
||||
quick pointers (hopefully only a few minutes each) to some of the places
|
||||
one can look to orient themselves and get started. Some of this will be
|
||||
general to window managers on X, much will be specific to Metacity, and
|
||||
there's probably some information that's common to programs in general but
|
||||
is nonetheless useful.
|
||||
|
||||
Overview
|
||||
Administrative issues
|
||||
Minimal Building/Testing Environment
|
||||
Relevant standards and X properties
|
||||
Debugging and testing
|
||||
Debugging logs
|
||||
Adding information to the log
|
||||
Valgrind
|
||||
Testing Utilities
|
||||
Technical gotchas to keep in mind
|
||||
Other important reading
|
||||
Extra reading
|
||||
Ideas for tasks to work on
|
||||
|
||||
|
||||
Administrative issues
|
||||
Don't commit substantive code in here without asking hp@redhat.com.
|
||||
Adding translations, no-brainer typo fixes, etc. is fine.
|
||||
|
||||
The code could use cleanup in a lot of places, feel free to do so.
|
||||
|
||||
See http://developer.gnome.org/dotplan/for_maintainers.html for
|
||||
information on how to make a release. The only difference from those
|
||||
instructions is that the minor version number of a Metacity release
|
||||
should always be a number from the Fibonacci sequence.
|
||||
|
||||
Minimal Building/Testing Environment
|
||||
You do not need to _install_ a development version of Metacity to
|
||||
build, run and test it; you can run it from some temporary
|
||||
directory. Also, you do not need to build all of Gnome in order to
|
||||
build a development version of Metacity -- odds are, you may be able
|
||||
to build metacity from CVS without building any other modules.
|
||||
|
||||
As long as you have gtk+ >= 3.0 and GIO >= 2.25.10 with your distro
|
||||
(gtk+ >= 2.6 if you manually revert the change from bug 348633), you
|
||||
should be able to install your distro's development packages
|
||||
(e.g. gtk2-devel, glib-devel, startup-notification-devel on
|
||||
Fedora; also, remember to install the gnome-common package which is
|
||||
needed for building cvs versions of Gnome modules like Metacity) as
|
||||
well as the standard development tools (gcc, autoconf, automake,
|
||||
pkg-config, intltool, and libtool) and be ready to build and test
|
||||
Metacity. Steps to do so:
|
||||
|
||||
$ svn checkout http://svn.gnome.org/svn/metacity/trunk metacity
|
||||
$ cd metacity
|
||||
$ ./autogen.sh --prefix /usr
|
||||
$ make
|
||||
$ ./src/metacity --replace
|
||||
|
||||
Again, note that you do not need to run 'make install'.
|
||||
|
||||
Relevant standards and X properties
|
||||
There are two documents that describe some basics about how window
|
||||
managers should behave: the ICCCM (Inter-Client Communication Conventions
|
||||
Manual) and EWMH (Extended Window Manager Hints). You can find these at
|
||||
the following locations:
|
||||
ICCCM - http://tronche.com/gui/x/icccm/
|
||||
EWMH - :pserver:anoncvs@pdx.freedesktop.org:/cvs
|
||||
The ICCCM is usually available in RPM or DEB format as well. There is
|
||||
actually an online version of the EWMH, but it is almost always woefully
|
||||
out of date. Just get it from cvs with these commands (the backslash
|
||||
means include the stuff from the next line):
|
||||
cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions login
|
||||
cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions \
|
||||
checkout wm-spec
|
||||
|
||||
DO NOT GO AND READ THOSE THINGS. THEY ARE REALLY, REALLY BORING.
|
||||
|
||||
If you do, you'll probably end up catching up on your sleep instead of
|
||||
hacking on Metacity. ;-) Instead, just look at the table of contents and
|
||||
glance at a page or two to get an idea of what's in there. Then only
|
||||
refer to it if you see something weird in the code and you don't know
|
||||
what it is but has some funny looking name like you see in one of those
|
||||
two documents.
|
||||
|
||||
You can refer to the COMPLIANCE file for additional information on these
|
||||
specifications and Metacity's compliance therewith.
|
||||
|
||||
One of the major things those documents cover that are useful to learn
|
||||
about immediately are X properties. The right way to learn about those,
|
||||
though, is through hand on experimentation with the xprop command (and
|
||||
then look up things you find from xprop in those two manuals if you're
|
||||
curious enough). First, try running
|
||||
xprop
|
||||
in a terminal and click on one of the windows on your screen. That gives
|
||||
you the x properties for that window. Look through them and get a basic
|
||||
idea of what's there for kicks. Note that you can get rid of some of the
|
||||
verboseness by grepping out the _NET_WM_ICON stuff, i.e.
|
||||
xprop | grep -v _NET_WM_ICON
|
||||
Next, try running
|
||||
xprop -root
|
||||
in a terminal. There's all the properties of the root window (which you
|
||||
can think of as the "main" Xserver window). You can also manually
|
||||
specify individual windows that you want the properties of with
|
||||
xprop -id <id>
|
||||
if you know the id of the window in question. You can get the id of a
|
||||
given window by either running xwininfo, e.g.
|
||||
xwininfo | grep "Window id" | cut -f 4 -d ' '
|
||||
or by looking at the _NET_CLIENT_STACKING property of the root
|
||||
window. Finally, it can also be useful to add "-spy" (without the
|
||||
quotes) to the xprop command to get it to continually monitor that
|
||||
window and report any changes to you.
|
||||
|
||||
Debugging information
|
||||
Trying to run a window manager under a typical debugger, such as gdb,
|
||||
unfortunately just doesn't work very well. So, we have to resort to
|
||||
other methods.
|
||||
|
||||
Debugging logs
|
||||
|
||||
First, note that you can start a new version of metacity to replace the
|
||||
existing one by running
|
||||
metacity --replace
|
||||
(which also comes in handy in the form "./src/metacity --replace" when
|
||||
trying to quickly test a small change while hacking on metacity without
|
||||
doing a full "make install", though I'm going off topic...) This will
|
||||
allow you to see any warnings printed at the terminal. Sometimes it's
|
||||
useful to have these directed to a logfile instead, which you can do by
|
||||
running
|
||||
METACITY_USE_LOGFILE=1 metacity --replace
|
||||
The logfile it uses will be printed in the terminal. Sometimes, it's
|
||||
useful to get more information than just warnings. You can set
|
||||
METACITY_VERBOSE to do that, like so:
|
||||
METACITY_VERBOSE=1 METACITY_USE_LOGFILE=1 metacity --replace
|
||||
(note that METACITY_VERBOSE=1 can be problematic without
|
||||
METACITY_USE_LOGFILE=1; avoid it unless running in from something that
|
||||
won't be managed by the new Metacity--see bug 305091 for more details).
|
||||
There are also other flags, such as METACITY_DEBUG, most of which I
|
||||
haven't tried and don't know what they do. Go to the source code
|
||||
directory and run
|
||||
grep "METACITY_" * | grep getenv
|
||||
to find out what the other ones are.
|
||||
|
||||
Adding information to the log
|
||||
|
||||
Since we can't single step with a debugger, we often have to fall back to
|
||||
the primitive method of getting information we want to know: adding
|
||||
"print" statements. Metacity has a fairly structured way to do this,
|
||||
using the functions meta_warning, meta_topic, and meta_verbose. All
|
||||
three have the same basic format as printf, except that meta_topic also
|
||||
takes a leading enumeration parameter to specify the type of message
|
||||
being shown (makes it easier for grepping in a verbose log). You'll find
|
||||
tons of examples in the source code if you need them; just do a quick
|
||||
grep or look in most any file. Note that meta_topic and meta_verbose
|
||||
messages only appear if verbosity is turned on. I tend to frequently add
|
||||
temporary meta_warning statements (or switch meta_topic or meta_verbose
|
||||
ones to meta_warning ones) and then undo the changes once I've learned
|
||||
the info that I needed.
|
||||
|
||||
There is also a meta_print_backtrace (which again is only active if
|
||||
verbosity is turned on) that can also be useful if you want to learn how
|
||||
a particular line of code gets called. And, of course, there's always
|
||||
g_assert if you want to make sure some section isn't executed (or isn't
|
||||
executed under certain conditions).
|
||||
|
||||
Valgrind
|
||||
|
||||
Valgrind is awesome for finding memory leaks or corruption and
|
||||
uninitialized variables. But I also tend to use it in a non-traditional
|
||||
way as a partial substitute for a normal debugger: it can provide me with
|
||||
a stack trace of where metacity is crashing if I made a change that
|
||||
caused it to do so, which is one of the major uses of debuggers. (And,
|
||||
what makes it cooler than a debugger is that there will also often be
|
||||
warnings pinpointing the cause of the crash from either some kind of
|
||||
simple memory corruption or an uninitialized variable). Sometimes, when
|
||||
I merely want to know what is calling a particular function I'll just
|
||||
throw in an "int i; printf("%d\n", i);" just because valgrind will give
|
||||
me a full stacktrace whenever it sees that uninitialized variable being
|
||||
used (yes, I could use meta_print_backtrace, but that means I have to
|
||||
turn verbosity on).
|
||||
|
||||
To run metacity under valgrind, use options typical for any Gnome
|
||||
program, such as
|
||||
valgrind --log-file=metacity.log --tool=memcheck --num-callers=48 \
|
||||
--leak-check=yes --leak-resolution=high --show-reachable=yes \
|
||||
./src/metacity --replace
|
||||
where, again, the backslashes mean to join all the stuff on the following
|
||||
line with the previous one.
|
||||
|
||||
However, there is a downside. Things run a little bit slowly, and it
|
||||
appears that you'll need about 1.5GB of ram, which unfortunately prevents
|
||||
most people from trying this.
|
||||
|
||||
Testing Utilities
|
||||
|
||||
src/run-metacity.sh
|
||||
The script src/run-metacity.sh is useful to hack on the window manager.
|
||||
It runs metacity in an Xnest. e.g.:
|
||||
CLIENTS=3 ./run-metacity.sh
|
||||
or
|
||||
DEBUG=memprof ./run-metacity.sh
|
||||
or
|
||||
DEBUG_TEST=1 ./run-metacity-sh
|
||||
or whatever.
|
||||
|
||||
metacity-message
|
||||
The tool metacity-message can be used as follows:
|
||||
metacity-message reload-theme
|
||||
metacity-message restart
|
||||
metacity-message enable-keybindings
|
||||
metacity-message disable-keybindings
|
||||
The first of these is useful for testing themes, the second is just
|
||||
another way (besides the --restart flag to metacity itself) of
|
||||
restarting metacity, and the third is useful for testing Metacity when
|
||||
running it under an Xnest (typically, the Metacity under the Xnest
|
||||
wouldn't get keybinding notifications--making keyboard navigation not
|
||||
work--but if you disable the keybindings for the global Metacity then
|
||||
the Metacity under the Xnest can then get those keybinding notifications).
|
||||
|
||||
metacity-window-demo
|
||||
metacity-window-demo is good for trying behavior of various kinds
|
||||
of window without launching a full desktop.
|
||||
|
||||
Technical gotchas to keep in mind
|
||||
Files that include gdk.h or gtk.h are not supposed to include
|
||||
display.h or window.h or other core files. Files in the core
|
||||
(display.[hc], window.[hc]) are not supposed to include gdk.h or
|
||||
gtk.h. Reasons:
|
||||
|
||||
"Basically you don't want GDK most of the time. It adds
|
||||
abstractions that cause problems, because they aren't designed to
|
||||
be used in a WM where we do weird stuff (display grabs, and just
|
||||
being the WM). At best GDK adds inefficiency, at worst it breaks
|
||||
things in weird ways where you have to be a GDK guru to figure
|
||||
them out. Owen also told me that they didn't want to start adding
|
||||
a lot of hacks to GDK to let a WM use it; we both agreed back in
|
||||
the mists of time that metacity would only use it for the "UI"
|
||||
bits as it does.
|
||||
|
||||
Having the split in the source code contains and makes very clear
|
||||
the interface between the WM and GDK/GTK. This keeps people from
|
||||
introducing extra GDK/GTK usage when it isn't needed or
|
||||
appropriate. Also, it speeds up the compilation a bit, though this
|
||||
was perhaps more relevant 5 years ago than it is now.
|
||||
|
||||
There was also a very old worry that the GDK stuff might have to
|
||||
be in a separate process to work right; that turned out to be
|
||||
untrue. Though who knows what issues the CM will introduce."
|
||||
|
||||
Remember that strings stored in X properties are not in UTF-8, and they
|
||||
have to end up in UTF-8 before we try putting them through Pango.
|
||||
|
||||
If you make any X request involving a client window, you have to
|
||||
meta_error_trap_push() around the call; this is not necessary for X
|
||||
requests on the frame windows.
|
||||
|
||||
Remember that not all windows have frames, and window->frame can be NULL.
|
||||
|
||||
Other important reading & where to get started
|
||||
Extra reading
|
||||
|
||||
There are some other important things to read to get oriented as well.
|
||||
These are:
|
||||
http://pobox.com/~hp/features.html
|
||||
rationales.txt
|
||||
doc/code-overview.txt
|
||||
|
||||
It pays to read http://pobox.com/~hp/features.html in order
|
||||
to understand the philosophy of Metacity.
|
||||
|
||||
The rationales.txt file has two things: (1) a list of design choices with
|
||||
links in the form of bugzilla bugs that discuss the issue, and (2) a list
|
||||
outstanding bug categories, each of which is tracked by a particular
|
||||
tracker bug in bugzilla from which you can find several closely related
|
||||
bug reports.
|
||||
|
||||
doc/code-overview.txt provides a fairly good overview of the code,
|
||||
including coverage of the function of the various files, the main
|
||||
structures and their relationships, and places to start looking in the
|
||||
code tailored to general categories of tasks.
|
||||
|
||||
Ideas for tasks to work on
|
||||
|
||||
There are a variety of things you could work on in the code. You may
|
||||
have ideas of your own, but in case you don't, let me provide a list of
|
||||
ideas you could choose from:
|
||||
|
||||
If you're ambitious, there's a list of things Havoc made that he'd really
|
||||
like to see tackled, which you can find at
|
||||
http://log.ometer.com/2004-05.html. Be sure to double check with someone
|
||||
to make sure the item is still relevant if you're interested in one of
|
||||
these. Another place to look for ideas, of course, is bugzilla. One can
|
||||
just do queries and look for things that look fixable.
|
||||
|
||||
However, perhaps the best way of getting ideas of related tasks to work
|
||||
on, is to look at the second half of the rationales.txt file, which tries
|
||||
to group bugs by type.
|
@ -1,8 +0,0 @@
|
||||
Tomas Frydrych
|
||||
Email: tf linux intel com
|
||||
Userid: tomasf
|
||||
|
||||
Owen Taylor
|
||||
Email: otaylor redhat com
|
||||
Userid: otaylor
|
||||
|
@ -1,43 +0,0 @@
|
||||
Currently active maintainers
|
||||
--------------------------------
|
||||
|
||||
Elijah Newren
|
||||
Email: newren gmail com
|
||||
Userid: newren
|
||||
|
||||
- Usually won't touch the theme bugs (isn't interested) or the
|
||||
compositor (until open source nvidia drivers are up to snuff).
|
||||
Tends to be most interested in libwnck/gtk interactions, focus
|
||||
issues, constraints problems, and raising/stacking, but works on
|
||||
just about anything other than themes and the compositor.
|
||||
|
||||
Thomas Thurman
|
||||
Email: thomas thurman org uk
|
||||
Userid: tthurman
|
||||
|
||||
- Responsible for all theme bugs and the compositor (thank goodness
|
||||
Thomas got involved, eh?). I'm sure he'll replace this sentence
|
||||
with his interests when he reads it. ;-)
|
||||
|
||||
|
||||
Semi-active maintainers
|
||||
--------------------------------
|
||||
|
||||
Havoc Pennington
|
||||
Email: hp redhat com
|
||||
Userid: hp
|
||||
- Original author. Doesn't patch metacity anymore, but is active in
|
||||
answering questions, responding to bugs, providing very helpful
|
||||
suggestions and insight, and even assisting with debugging.
|
||||
|
||||
|
||||
Important historical figureheads
|
||||
--------------------------------
|
||||
|
||||
Rob Adams (readams readams net)
|
||||
- Was the main maintainer of metacity for a while; particular areas
|
||||
of focus included xinerama, placement, and an older version of the
|
||||
constraints code. Still responds to bugs every once in a while.
|
||||
|
||||
Søren Sandmann (sandmann redhat com)
|
||||
- Wrote most of the current compositing manager code + libcm
|
@ -3,8 +3,6 @@ SUBDIRS=src po doc
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
|
||||
EXTRA_DIST = HACKING MAINTAINERS rationales.txt
|
||||
|
||||
DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
|
||||
|
164
NEWS
164
NEWS
@ -1,23 +1,21 @@
|
||||
3.12.0
|
||||
======
|
||||
* Fix grab issue with SSD xwayland windows [Rui; #726123]
|
||||
* Misc. bug fixes [Jasper, Ray, Rui, Florian; #727011]
|
||||
|
||||
Translations:
|
||||
Ask H. Larsen [da], Мирослав Николић [sr, sr@latin], Andika Triwidada [id],
|
||||
Daniel Korostil [uk], Petr Kovar [cs]
|
||||
Contributors:
|
||||
Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode
|
||||
|
||||
3.11.92
|
||||
=======
|
||||
* Fix identification of CSD windows [Owen; #723029]
|
||||
* Add minimal handling of touch events [Carlos; #723552]
|
||||
* Misc bug fixes and cleanups [Owen, Adel, Jasper; #723580, #726352]
|
||||
* Update keyboard state unconditionally [Rui; #722847]
|
||||
* Misc bug fixes and cleanups [Owen, Rui, Giovanni, Matthias, Adel, Ryan,
|
||||
Jasper, Marek, Florian; #723580, #726123, #726683]
|
||||
|
||||
Contributors:
|
||||
Adel Gadllah, Carlos Garnacho, Rui Matos, Jasper St. Pierre, Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Changwoo Ryu [ko], Rūdolfs Mazurs [lv], Wylmer Wang [zh_CN],
|
||||
Chao-Hsiung Liao [zh_HK, zh_TW], Yuri Myasoedov [ru], Tiagosdot [pt],
|
||||
Claude Paroz [fr], Duarte Loreto [pt], A S Alam [pa]
|
||||
Giovanni Campagna, Marek Chalupa, Matthias Clasen, Adel Gadllah, Ryan Lortie,
|
||||
Rui Matos, Florian Müllner, Jasper St. Pierre, Owen W. Taylor
|
||||
|
||||
3.11.91
|
||||
=======
|
||||
@ -26,125 +24,104 @@ Translations:
|
||||
* Improve keybinding lookups [Rui; #725588]
|
||||
* Fix dynamic updates of titlebar style properties [Owen; #725751]
|
||||
* Fix positioning of manually positioned windows [Owen; #724049]
|
||||
* Misc. bug fixes [Carlos, Giovanni, Florian, Jasper; #724969, #724402, #722266,
|
||||
#725338]
|
||||
* Misc bug fixes and cleanups [Jasper, Carlos, Adel, Giovanni, Florian; #720631,
|
||||
#724969, #725216, #724402, #722266, #725338, #725525]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Adel Gadllah, Carlos Garnacho, Rui Matos, Florian Müllner,
|
||||
Jasper St. Pierre
|
||||
|
||||
Translations:
|
||||
Aurimas Černius [lt], Milo Casagrande [it], Balázs Úr [hu],
|
||||
Matej Urbančič [sl], Enrico Nicoletto [pt_BR], Yosef Or Boczko [he],
|
||||
Piotr Drąg [pl], Fran Diéguez [gl]
|
||||
Jasper St. Pierre, Owen W. Taylor
|
||||
|
||||
3.11.90
|
||||
=======
|
||||
* Use correct output property for backlight control [Robert; #723606]
|
||||
* Fix double-scaling on high DPI resolutions [Adel; #723931]
|
||||
* Make tile previews a compositor effect [Stefano, Florian; #665758]
|
||||
* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper; #722530, #724257,
|
||||
#724258, #724364, #720631, #707851, #707897]
|
||||
* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper, Adel; #722530, #724257,
|
||||
#724258, #720631, #724364, #724472]
|
||||
|
||||
Contributors:
|
||||
Robert Ancell, Giovanni Campagna, Stefano Facchini, Adel Gadllah,
|
||||
Giovanni Campagna, Marek Chalupa, Stefano Facchini, Adel Gadllah,
|
||||
Ryan Lortie, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz
|
||||
|
||||
Translations:
|
||||
Shankar Prasad [kn], Khaled Hosny [ar], Marek Černocký [cs],
|
||||
Kjartan Maraas [nb], Daniel Korostil [uk]
|
||||
|
||||
3.11.5
|
||||
======
|
||||
* Fix CSD titlebars being placed off-screen [Jasper; #719772]
|
||||
* Add support for subsurfaces [Jonas; #705502]
|
||||
* Expose MetaWindow:skip-taskbar property [Florian; #723307]
|
||||
* Fix legacy tray icons showing up blank [Adel; #721596]
|
||||
* Fix configuration of cloned monitors [Adel; #710610]
|
||||
* Misc bug fixes and cleanups [Jasper, Adel, Jonas; #720631, #723468, #723563]
|
||||
* Misc bug fixes and cleanups [Jasper, Adel, Marek, Jonas; #720631, #723468,
|
||||
#720818, #723563, #723564]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Marek Ch, Adel Gadllah, Florian Müllner, Jasper St. Pierre
|
||||
|
||||
Translations:
|
||||
Rafael Ferreira [pt_BR], Enrico Nicoletto [pt_BR], Fran Diéguez [gl],
|
||||
Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||
|
||||
3.11.4
|
||||
======
|
||||
* Don't leave focus on windows that are being unmanaged [Owen; #711618]
|
||||
* Reduce server grabs [Daniel Drake; #721345, #721709]
|
||||
* Improve heuristic to determine display output name [Cosimo Cecchi; #721674]
|
||||
* Atomically unmaximize both directions [Jasper; #722108]
|
||||
* Misc bug fixes [Debarshi, Andika; #721517, #721674]
|
||||
* Misc bug fixes [Debarshi, Andika, Florian; #721517, #721674, #722347]
|
||||
|
||||
Contributors:
|
||||
Cosimo Cecchi, Daniel Drake, Debarshi Ray, Jasper St. Pierre,
|
||||
Cosimo Cecchi, Daniel Drake, Florian Müllner, Debarshi Ray, Jasper St. Pierre,
|
||||
Andika Triwidada, Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Rafael Ferreira [pt_BR], Dimitris Spingos [el], Daniel Mustieles [es],
|
||||
Milo Casagrande [it], Yosef Or Boczko [he]
|
||||
|
||||
3.11.3
|
||||
======
|
||||
* xrandr: Use "hotplug_mode_update" property [Marc-André; #711216]
|
||||
* Fix position of attached dialogs for CSD windows [Giovanni, Owen; #707194]
|
||||
* Fix focus issues with external OSKs [Jasper; #715030]
|
||||
* Fix focus issues with external OSKs[Jasper; #715030]
|
||||
* Add a MetaCullable interface [Jasper; #714706]
|
||||
* Fix window keybindings [Rui; #719724]
|
||||
* Fix settings keyboard/pointer focus for new clients [Rui; #719725]
|
||||
* Fix window group paint volume [Owen; #719669]
|
||||
* Fix frame extents problems [Owen; #714707]
|
||||
* Add shortcut to move windows between monitors [Florian; #671054]
|
||||
* Fix problems with focus tracking [Owen; #720558]
|
||||
* Misc. bug fixes and cleanups [Rui, Jasper, Owen; #712833, #678989, #720106,
|
||||
#720417, #720630]
|
||||
* Misc. bug fixes and cleanups: [Rui, Colin, Lionel, Jasper, Owen; #712833,
|
||||
#719557, #719695, #719833, #678989, #720417, #720630]
|
||||
|
||||
Contributors:
|
||||
Robert Bragg, Giovanni Campagna, Marc-André Lureau, Rui Matos, Alberto Milone,
|
||||
Florian Müllner, Sindhu S, Jasper St. Pierre, Rico Tzschichholz,
|
||||
Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
甘露(Gan Lu) [zh_CN], Khaled Hosny [ar]
|
||||
Lionel Landwerlin, Rui Matos, Alberto Milone, Florian Müllner,
|
||||
Jasper St. Pierre, Rico Tzschichholz, Owen W. Taylor, Colin Walters
|
||||
|
||||
3.11.2
|
||||
======
|
||||
* Support setting a NULL opaque region [Andreas; #711518]
|
||||
* Sync keymap from X to wayland [Giovanni; #707446]
|
||||
* Implement support for subsurfaces [Jonas; #705502]
|
||||
* Don't focus the no-focus-window for globally active windows [Jasper; #710296]
|
||||
* Support "hotplug_mode_update" property [Marc-André; #711216]
|
||||
* Fix resize operations using mouse-button-modifier [Lionel; #710251]
|
||||
* Misc. fixes and cleanups [Jasper, Rico, Florian; #711731]
|
||||
* Fix position of attached modals for CSD windows [Giovanni, Owen; #707194]
|
||||
* Misc. bug fixes [Rui, Jasper, Neil, Florian; #712247, #711731]
|
||||
|
||||
Contributors:
|
||||
Lionel Landwerlin, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz
|
||||
Giovanni Campagna, Andreas Heider, Lionel Landwerlin, Marc-André Lureau,
|
||||
Rui Matos, Florian Müllner, Neil Roberts, Sindhu S, Jasper St. Pierre,
|
||||
Rico Tzschichholz, Owen W. Taylor, Jonas Ådahl
|
||||
|
||||
3.11.1
|
||||
======
|
||||
* Don't require at least one output device to be connected [Giovanni; #709009]
|
||||
* Name the guard window [Andrew; #710346]
|
||||
* Fix tile previews getting stuck on right click during drags [Lionel; #704759]
|
||||
* Use new UPower API [Bastien]
|
||||
* Set hot spot when cursor set from wl_buffer [Jonas; #709593]
|
||||
* Expose min-backlight-step [Asad; #710380]
|
||||
* Don't focus the no-focus-window for globally active windows [Jasper; #710296]
|
||||
* Misc. fixes and cleanups [Jasper, Rico, Olav, Magdalen; #709776]
|
||||
* Misc. bug fixes and cleanups [Jasper, Olav, Magdalen; #709776]
|
||||
|
||||
Contributors:
|
||||
Magdalen Berns, Giovanni Campagna, Asad Mehmood, Bastien Nocera,
|
||||
Jasper St. Pierre, Rico Tzschichholz, Olav Vitters, Andrew Walton
|
||||
|
||||
Translations:
|
||||
Reinout van Schouwen [nl]
|
||||
Magdalen Berns, Lionel Landwerlin, Asad Mehmood, Bastien Nocera,
|
||||
Jasper St. Pierre, Olav Vitters, Jonas Ådahl
|
||||
|
||||
3.10.1
|
||||
======
|
||||
* Don't apply fullscreen workarounds to CSD windows [Giovanni; #708718]
|
||||
* Fix hangs during DND operations [Adel; #709340]
|
||||
* Use nearest-pixel interpolation when possible [Hans; #708389]
|
||||
* Fix tile previews getting stuck on right click during drags [Lionel; #704759]
|
||||
* Misc bug fixes [Giovanni, Jasper; #708420]
|
||||
* Misc bug fixes [Dan, Giovanni, Jasper; #708813, #708420]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Adel Gadllah, Lionel Landwerlin, Hans Petter Jansson,
|
||||
Giovanni Campagna, Adel Gadllah, Dan Horák, Hans Petter Jansson,
|
||||
Jasper St. Pierre
|
||||
|
||||
Translations:
|
||||
Khaled Hosny [ar], Reinout van Schouwen [nl], Carles Ferrando [ca@valencia]
|
||||
|
||||
3.10.0.1
|
||||
========
|
||||
* Fix bug when a window changed size twice in a single frame - this
|
||||
@ -155,24 +132,32 @@ Contributors:
|
||||
|
||||
3.10.0
|
||||
======
|
||||
|
||||
Translations:
|
||||
Ask H. Larsen [da], Gabor Kelemen [hu], Duarte Loreto [pt],
|
||||
Yosef Or Boczko [he]
|
||||
* Update dependencies [Giovanni; #708210]
|
||||
|
||||
3.9.92
|
||||
======
|
||||
* Don't create a dummy texture for the texture pipeline template [Neil; #707458]
|
||||
* Remove holes generated by disabling the laptop lid [Giovanni; #707473]
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=707474 [Giovanni; #707474]
|
||||
* Constrain the pointer position onto visible monitors [Giovanni; #706655]
|
||||
* Fix keyboard state handling in face of event compression [Giovanni; #706963]
|
||||
* Extend the MetaCursorTracker API with query pointer and cursor visibility [Giovanni; #707474]
|
||||
* Be stricter in checking and exposing the wayland protocol version [#707851]
|
||||
* Don't require plugins to pass event to Clutter [Giovanni; #707482]
|
||||
* Move the --wayland option from the binary to the library [Giovanni; #707897]
|
||||
* Implement running from gnome-session (environment variable setting, process group
|
||||
handling, Clutter backend variables) [Giovanni; #706421]
|
||||
* Add support for more cursor types [Giovanni; #707919]
|
||||
* Drop man pages for removed utilities [Kalev; #706579]
|
||||
* Implement monitor configuration on KMS [Giovanni; #706308]
|
||||
* Implement HW cursors [Giovanni; #707573]
|
||||
* Implement minimal support for resizing and maximizing wayland clients [Giovanni; #707401]
|
||||
* Implement transient hints for wayland clients [Giovanni; #707401]
|
||||
* Implement popup menu surfaces and grabs [Giovanni; #707863]
|
||||
* Immediately fire idle watches that are already expired [Giovanni; #707302]
|
||||
* Misc bug fixes [Giovanni, Colin, Pavel; #707649, #707563, #708070]
|
||||
* Remove holes generated by disabling the laptop lid [Giovanni; #707473]
|
||||
* Misc bug fixes [Giovanni, Pavel, Adel; #707649, #706124, #707584, #707851, #707929,
|
||||
#708070]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Adel Gadllah, Colin Guthrie, Neil Roberts,
|
||||
Jasper St. Pierre, Ray Strode, Pavel Vasin
|
||||
Adel Gadllah, Giovanni Campagna, Kalev Lember, Pavel Vasin
|
||||
|
||||
Translations:
|
||||
Мирослав Николић po/sr, sr@latin.po, Мирослав Николић [sr, sr@latin],
|
||||
@ -185,19 +170,30 @@ Translations:
|
||||
3.9.91
|
||||
======
|
||||
* Drop man pages for removed utilities [Kalev; #706579]
|
||||
* Add support for idle tracking [Giovanni; #706005]
|
||||
* Add support for idle tracking [Giovanni, Cosimo; #706005, #707250]
|
||||
* Skip CRTC reconfigurations that have no effect [Giovanni; #706672]
|
||||
* Ignore skip-taskbar hints on parentless dialogs [Giovanni; #673399]
|
||||
* Don't save pixbuf data in user data [Tim; #706777]
|
||||
* Don't queue redraws for obscured regions [Adel; #703332]
|
||||
* Turn blending off when drawing entirely opaque regions [Jasper; #706930]
|
||||
* Suppor the opaque region hints for wayland clients [Jasper; #707019]
|
||||
* Turn blending off when drawing entirely opaque regions [Jasper; #707019]
|
||||
* Check event timestamps before reconfiguring [Giovanni; #706735]
|
||||
* Merge the DBus API for display configuration in the wayland branch [Giovanni]
|
||||
* Install an X IO error handler for XWayland [Giovanni; #706962]
|
||||
* Use the clutter xkbcommon integration for the wayland keyboard [Giovanni; #705862]
|
||||
* Add a setuid helper for running on KMS+evdev [Giovanni, Colin; #705861]
|
||||
* Add keybindings for switching VT [Giovanni; #705861]
|
||||
* Implement plugin modality when running as a wayland compositor [Giovanni; #705917]
|
||||
* Add support for the application menu for wayland clients [Giovanni; #707128]
|
||||
* Several Coverity spotted fixes [Jasper]
|
||||
* Don't create a dummy texture for the texture template [Neil; #707458]
|
||||
* Use a more conservative paint volume for obscured windows [Adel]
|
||||
* Misc bug fixes [Giovanni, Colin, Seán, Jasper, Cosimo; #706582, #706598,
|
||||
#706787, #706729, #706825, #707081, #707090, #707250, #707267]
|
||||
#706787, #706729, #706825, #707081, #707090, #707267, #706982, #706289]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Cosimo Cecchi, Adel Gadllah, Colin Guthrie, Kalev Lember,
|
||||
Tim Lunn, Jasper St. Pierre, Rico Tzschichholz, Seán de Búrca
|
||||
Tim Lunn, Jasper St. Pierre, Neil Roberts, Rico Tzschichholz, Seán de Búrca
|
||||
|
||||
Translations:
|
||||
Piotr Drąg [pl], Alexandre Franke [fr], Kjartan Maraas [nb],
|
||||
@ -206,6 +202,8 @@ Translations:
|
||||
|
||||
3.9.90
|
||||
======
|
||||
* First release from the wayland branch, includes basic support for running
|
||||
as a wayland compositor [Robert, Neil, Giovanni]
|
||||
* Add support for _GTK_FRAME_EXTENTS [Jasper; #705766]
|
||||
* Fix quick consecutive <super> presses breaking keyboard input [Alban; #666101]
|
||||
* Work towards running as wayland compositor [Giovanni]
|
||||
@ -220,8 +218,8 @@ Translations:
|
||||
|
||||
Contributors:
|
||||
Robert Bragg, Giovanni Campagna, Alban Crequy, Adel Gadllah,
|
||||
Alexander Larsson, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz,
|
||||
Colin Walters
|
||||
Alexander Larsson, Florian Müllner, Jasper St. Pierre, Neil Roberts,
|
||||
Rico Tzschichholz, Colin Walters
|
||||
|
||||
Translations:
|
||||
Jiro Matsuzawa [ja], Kjartan Maraas [nb], Matej Urbančič [sl],
|
||||
|
416
README
416
README
@ -1,416 +0,0 @@
|
||||
The original codebase named "Metacity" is not a meta-City as in an
|
||||
urban center, but rather Meta-ness as in the state of being
|
||||
meta. i.e. metacity : meta as opacity : opaque. Also it may have
|
||||
something to do with the Meta key on UNIX keyboards.
|
||||
|
||||
Since then, it has been renamed mutter after a rebase on top of
|
||||
clutter as a compositing manager.
|
||||
|
||||
COMPILING MUTTER
|
||||
===
|
||||
|
||||
You need GTK+ 2.2. For startup notification to work you need
|
||||
libstartup-notification at
|
||||
http://www.freedesktop.org/software/startup-notification/ or on the
|
||||
GNOME ftp site.
|
||||
You need Clutter 1.0. You need gobject-introspection 0.6.3.
|
||||
|
||||
REPORTING BUGS AND SUBMITTING PATCHES
|
||||
===
|
||||
|
||||
Report new bugs on http://bugzilla.gnome.org. Please check for
|
||||
duplicates, *especially* if you are reporting a feature request.
|
||||
|
||||
Please do *not* add "me too!" or "yes I really want this!" comments to
|
||||
feature requests in bugzilla. Please read
|
||||
http://pobox.com/~hp/features.html prior to adding any kind of flame
|
||||
about missing features or misfeatures.
|
||||
|
||||
Feel free to send patches too; Metacity is relatively small and
|
||||
simple, so if you find a bug or want to add a feature it should be
|
||||
pretty easy. Send me mail, or put the patch in bugzilla.
|
||||
|
||||
See the HACKING file for some notes on hacking Mutter.
|
||||
|
||||
MUTTER FEATURES
|
||||
===
|
||||
|
||||
- Uses GTK+ 2.0 for drawing window frames. This means colors, fonts,
|
||||
etc. come from GTK+ theme.
|
||||
|
||||
- Does not expose the concept of "window manager" to the user. Some
|
||||
of the features in the GNOME control panel and other parts of the
|
||||
desktop happen to be implemented in metacity, such as changing your
|
||||
window border theme, or changing your window navigation shortcuts,
|
||||
but the user doesn't need to know this.
|
||||
|
||||
- Includes only the window manager; does not try to be a desktop
|
||||
environment. The pager, configuration, etc. are all separate and
|
||||
modular. The "libwnck" library (which I also wrote) is available
|
||||
for writing metacity extensions, pagers, and so on. (But libwnck
|
||||
isn't metacity specific, or GNOME-dependent; it requires only GTK,
|
||||
and should work with KWin, fvwm2, and other EWMH-compliant WMs.)
|
||||
|
||||
- Has a simple theme system and a couple of extra themes come with it.
|
||||
Change themes via gsettings:
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Crux
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Gorilla
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Atlanta
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Bright
|
||||
|
||||
See theme-format.txt for docs on the theme format. Use
|
||||
metacity-theme-viewer to preview themes.
|
||||
|
||||
- Change number of workspaces via gsettings:
|
||||
gsettings set org.gnome.desktop.wm.preferences num-workspaces 5
|
||||
|
||||
Can also change workspaces from GNOME 2 pager.
|
||||
|
||||
- Change focus mode:
|
||||
gsettings set org.gnome.desktop.wm.preferences focus-mode mouse
|
||||
gsettings set org.gnome.desktop.wm.preferences focus-mode sloppy
|
||||
gsettings set org.gnome.desktop.wm.preferences focus-mode click
|
||||
|
||||
- Global keybinding defaults include:
|
||||
|
||||
Alt-Tab forward cycle window focus
|
||||
Alt-Shift-Tab backward cycle focus
|
||||
Alt-Ctrl-Tab forward cycle focus among panels
|
||||
Alt-Ctrl-Shift-Tab backward cycle focus among panels
|
||||
Alt-Escape cycle window focus without a popup thingy
|
||||
Ctrl-Alt-Left Arrow previous workspace
|
||||
Ctrl-Alt-Right Arrow next workspace
|
||||
Ctrl-Alt-D minimize/unminimize all, to show desktop
|
||||
|
||||
Change keybindings for example:
|
||||
|
||||
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 '[<Alt>F1]'
|
||||
|
||||
Also try the GNOME keyboard shortcuts control panel.
|
||||
|
||||
- Window keybindings:
|
||||
|
||||
Alt-space window menu
|
||||
|
||||
Mnemonics work in the menu. That is, Alt-space then underlined
|
||||
letter in the menu item works.
|
||||
|
||||
Choose Move from menu, and arrow keys to move the window.
|
||||
|
||||
While moving, hold down Control to move slower, and
|
||||
Shift to snap to edges.
|
||||
|
||||
Choose Resize from menu, and nothing happens yet, but
|
||||
eventually I might implement something.
|
||||
|
||||
Keybindings for things like maximize window, vertical maximize,
|
||||
etc. can be bound, but may not all exist by default. See
|
||||
metacity.schemas.
|
||||
|
||||
- Window mouse bindings:
|
||||
|
||||
Clicking anywhere on frame with button 1 will raise/focus window
|
||||
|
||||
If you click a window control, such as the close button, then the
|
||||
control will activate on button release if you are still over it
|
||||
on release (as with most GUI toolkits)
|
||||
|
||||
If you click and drag borders with button 1 it resizes the window
|
||||
|
||||
If you click and drag the titlebar with button 1 it moves the
|
||||
window.
|
||||
|
||||
If you click anywhere on the frame with button 2 it lowers the
|
||||
window.
|
||||
|
||||
If you click anywhere on the frame with button 3 it shows the
|
||||
window menu.
|
||||
|
||||
If you hold down Super (windows key) and click inside a window, it
|
||||
will move the window (buttons 1 and 2) or show menu (button 3).
|
||||
Or you can configure a different modifier for this.
|
||||
|
||||
If you pick up a window with button 1 and then switch workspaces
|
||||
the window will come with you to the new workspace, this is
|
||||
a feature copied from Enlightenment.
|
||||
|
||||
If you hold down Shift while moving a window, the window snaps
|
||||
to edges of other windows and the screen.
|
||||
|
||||
- Session management:
|
||||
|
||||
Mutter connects to the session manager and will set itself up to
|
||||
be respawned. It theoretically restores sizes/positions/workspace
|
||||
for session-aware applications.
|
||||
|
||||
- Mutter implements much of the EWMH window manager specification
|
||||
from freedesktop.org, as well as the older ICCCM. Please refer to
|
||||
the COMPLIANCE file for information on mutter compliance with
|
||||
these standards.
|
||||
|
||||
- Uses Pango to render text, so has cool i18n capabilities.
|
||||
Supports UTF-8 window titles and such.
|
||||
|
||||
- There are simple animations for actions such as minimization,
|
||||
to help users see what is happening. Should probably
|
||||
have a few more of these and make them nicer.
|
||||
|
||||
- if you have the proper X setup, set the GDK_USE_XFT=1
|
||||
environment variable to get antialiased window titles.
|
||||
|
||||
- considers the panel when placing windows and maximizing
|
||||
them.
|
||||
|
||||
- handles the window manager selection from the ICCCM. Will exit if
|
||||
another WM claims it, and can claim it from another WM if you pass
|
||||
the --replace argument. So if you're running another
|
||||
ICCCM-compliant WM, you can run "mutter --replace" to replace it
|
||||
with Metacity.
|
||||
|
||||
- does basic colormap handling
|
||||
|
||||
- and much more! well, maybe not a lot more.
|
||||
|
||||
HOW TO ADD EXTERNAL FEATURES
|
||||
===
|
||||
|
||||
You can write a mutter "plugin" such as a pager, window list, icon
|
||||
box, task menu, or even things like "window matching" using the
|
||||
Extended Window Manager Hints. See http://www.freedesktop.org for the
|
||||
EWMH specification. An easy-to-use library called "libwnck" is
|
||||
available that uses the EWMH and is specifically designed for writing
|
||||
WM accessories.
|
||||
|
||||
You might be interested in existing accessories such as "Devil's Pie"
|
||||
by Ross Burton, which add features to Mutter (or other
|
||||
EWMH-compliant WMs).
|
||||
|
||||
MUTTER BUGS, NON-FEATURES, AND CAVEATS
|
||||
===
|
||||
|
||||
See bugzilla: http://bugzilla.gnome.org/query.cgi
|
||||
|
||||
FAQ
|
||||
===
|
||||
|
||||
Q: Will you add my feature?
|
||||
|
||||
A: If it makes sense to turn on unconditionally, or is genuinely a
|
||||
harmless preference that I would not be embarrassed to put in a
|
||||
simple, uncluttered, user-friendly configuration dialog.
|
||||
|
||||
If the only rationale for your feature is that other window
|
||||
managers have it, or that you are personally used to it, or
|
||||
something like that, then I will not be impressed. Metacity is
|
||||
firmly in the "choose good defaults" camp rather than the "offer 6
|
||||
equally broken ways to do it, and let the user pick one" camp.
|
||||
|
||||
This is part of a "no crackrock" policy, despite some exceptions
|
||||
I'm mildly embarrassed about. For example, multiple workspaces
|
||||
probably constitute crackrock, they confuse most users and really
|
||||
are not that useful if you have a decent tasklist and so on. But I
|
||||
am too used to them to turn them off. Or alternatively
|
||||
iconification/tasklist is crack, and workspaces/pager are good. But
|
||||
having both is certainly a bit wrong. Sloppy focus is probably
|
||||
crackrock too.
|
||||
|
||||
But don't think unlimited crack is OK just because I slipped up a
|
||||
little. No slippery slope here.
|
||||
|
||||
Don't let this discourage patches and fixes - I love those. ;-)
|
||||
Just be prepared to hear the above objections if your patch adds
|
||||
some crack-ridden configuration option.
|
||||
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Will Mutter be part of GNOME?
|
||||
|
||||
A: It is not officially part of GNOME as of GNOME 2.27. We are
|
||||
hoping to have mutter officially included as of GNOME 2.28.
|
||||
|
||||
Q: Why does Mutter remember the workspace/position of some apps
|
||||
but not others across logout/login?
|
||||
|
||||
A: Mutter only stores sizes/positions for apps that are session
|
||||
managed. As far as I can determine, there is no way to attempt to
|
||||
remember workspace/position for non-session-aware apps without
|
||||
causing a lot of weird effects.
|
||||
|
||||
The reason is that you don't know which non-SM-aware apps were
|
||||
launched by the session. When you initially log in, Metacity sees a
|
||||
bunch of new windows appear. But it can't distinguish between
|
||||
windows that were stored in your session, or windows you just
|
||||
launched after logging in. If Metacity tried to guess that a window
|
||||
was from the session, it could e.g. end up maximizing a dialog, or
|
||||
put a window you just launched on another desktop or in a weird
|
||||
place. And in fact I see a lot of bugs like this in window managers
|
||||
that try to handle non-session-aware apps.
|
||||
|
||||
However, for session-aware apps, Mutter can tell that the
|
||||
application instance is from the session and thus restore it
|
||||
reliably, assuming the app properly restores the windows it had
|
||||
open on session save.
|
||||
|
||||
So the correct way to fix the situation is to make apps
|
||||
session-aware. libSM has come with X for years, it's very
|
||||
standardized, it's shared by GNOME and KDE - even twm is
|
||||
session-aware. So anyone who won't take a patch to add SM is more
|
||||
archaic than twm - and you should flame them. ;-)
|
||||
|
||||
Docs on session management:
|
||||
http://www.fifi.org/doc/xspecs/xsmp.txt.gz
|
||||
http://www.fifi.org/doc/xspecs/SMlib.txt.gz
|
||||
|
||||
See also the ICCCM section on SM. For GNOME apps, use the
|
||||
GnomeClient object. For a simple example of using libSM directly,
|
||||
twm/session.c in the twm source code is pretty easy to understand.
|
||||
|
||||
Q: How about adding viewports in addition to workspaces?
|
||||
|
||||
A: I could conceivably be convinced to use viewports _instead_ of
|
||||
workspaces, though currently I'm not thinking that. But I don't
|
||||
think it makes any sense to have both; it's just confusing. They
|
||||
are functionally equivalent.
|
||||
|
||||
You may think this means that you won't have certain keybindings,
|
||||
or something like that. This is a misconception. The only
|
||||
_fundamental_ difference between viewports and workspaces is that
|
||||
with viewports, windows can "overlap" and appear partially on
|
||||
one and partially on another. All other differences that
|
||||
traditionally exist in other window managers are accidental -
|
||||
the features commonly associated with viewports can be implemented
|
||||
for workspaces, and vice versa.
|
||||
|
||||
So I don't want to have two kinds of
|
||||
workspace/desktop/viewport/whatever, but I'm willing to add
|
||||
features traditionally associated with either kind if those
|
||||
features make sense.
|
||||
|
||||
Q: Why is the panel always on top?
|
||||
|
||||
A: Because it's a better user interface, and until we made this not
|
||||
configurable a bunch of apps were not getting fixed (the app
|
||||
authors were just saying "put your panel on the bottom" instead of
|
||||
properly supporting fullscreen mode, and such).
|
||||
|
||||
rationales.txt has the bugzilla URL for some flamefesting on this,
|
||||
if you want to go back and relive the glory.
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Why is there no edge flipping?
|
||||
|
||||
A: This one is also in rationales.txt. Because "ouija board" UI, where
|
||||
you just move the mouse around and the computer guesses what you
|
||||
mean, has a lot of issues. This includes mouse focus, shade-hover
|
||||
mode, edge flipping, autoraise, etc. Metacity has mouse focus and
|
||||
autoraise as a compromise, but these features are all confusing for
|
||||
many users, and cause problems with accessibility, fitt's law, and
|
||||
so on.
|
||||
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Why does wireframe move/resize suck?
|
||||
|
||||
A: You can turn it on with the reduced_resources setting.
|
||||
|
||||
But: it has low usability, and is a pain
|
||||
to implement, and there's no reason opaque move/resize should be a
|
||||
problem on any setup that can run a modern desktop worth a darn to
|
||||
begin with.
|
||||
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
The reason we had to add wireframe anyway was broken
|
||||
proprietary apps that can't handle lots of resize events.
|
||||
|
||||
Q: Why no XYZ?
|
||||
|
||||
A: You are probably getting the idea by now - check rationales.txt,
|
||||
query/search bugzilla, and read http://pobox.com/~hp/features.html
|
||||
and http://pobox.com/~hp/free-software-ui.html
|
||||
|
||||
Then sit down and answer the question for yourself. Is the feature
|
||||
good? What's the rationale for it? Answer "why" not just "why not."
|
||||
Justify in terms of users as a whole, not just users like
|
||||
yourself. How else can you solve the same problem? etc. If that
|
||||
leads you to a strong opinion, then please, post the rationale for
|
||||
discussion to an appropriate bugzilla bug, or to
|
||||
usability@gnome.org.
|
||||
|
||||
Please don't just "me too!" on bugzilla bugs, please don't think
|
||||
flames will get you anywhere, and please don't repeat rationale
|
||||
that's already been offered.
|
||||
|
||||
Q: Your dumb web pages you made me read talk about solving problems in
|
||||
fundamental ways instead of adding preferences or workarounds.
|
||||
What are some examples where metacity has done this?
|
||||
|
||||
A: There are quite a few, though many opportunities remain. Sometimes
|
||||
the real fix involves application changes. The metacity approach is
|
||||
that it's OK to require apps to change, though there are also
|
||||
plenty of workarounds in metacity for battles considered too hard
|
||||
to fight.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- fullscreen mode was introduced to allow position constraints,
|
||||
panel-on-top, and other such things to apply to normal windows
|
||||
while still allowing video players etc. to "just work"
|
||||
|
||||
- "whether to include minimized windows in Alt+Tab" was solved
|
||||
by putting minimized windows at the *end* of the tab order.
|
||||
|
||||
- Whether to pop up a feedback display during Alt+Tab was solved by
|
||||
having both Alt+Tab and Alt+Esc
|
||||
|
||||
- Whether to have a "kill" feature was solved by automatically
|
||||
detecting and offering to kill stuck apps. Better, metacity
|
||||
actually does "kill -9" on the process, it doesn't just
|
||||
disconnect the process from the X server. You'll appreciate this
|
||||
if you ever did a "kill" on Netscape 4, and watched it keep
|
||||
eating 100% CPU even though the X server had booted it.
|
||||
|
||||
- The workspaces vs. viewports mess was avoided by adding
|
||||
directional navigation and such to workspaces, see discussion
|
||||
earlier in this file.
|
||||
|
||||
- Instead of configurable placement algorithms, there's just one
|
||||
that works fairly well most of the time.
|
||||
|
||||
- To avoid excess CPU use during opaque move/resize, we rate limit
|
||||
the updates to the application window's size.
|
||||
|
||||
- Instead of configurable "show size of window while resizing,"
|
||||
it's only shown for windows where it matters, such as terminals.
|
||||
(Only use-case given for all windows is for web designers
|
||||
choosing their web browser size, but there are web sites and
|
||||
desktop backgrounds that do this for you.)
|
||||
|
||||
- Using startup notification, applications open on the workspace
|
||||
where you launched them, not the active workspace when their
|
||||
window is opened.
|
||||
|
||||
- and much more.
|
||||
|
||||
Q: I think mutter sucks.
|
||||
|
||||
A: Feel free to use any WM you like. The reason metacity follows the
|
||||
ICCCM and EWMH specifications is that it makes metacity a modular,
|
||||
interchangeable part in the desktop. libwnck-based apps such as the
|
||||
GNOME window list will work just fine with any EWMH-compliant WM.
|
||||
|
||||
Q: Did you spend a lot of time on this?
|
||||
|
||||
A: Originally the answer was no. Sadly the answer is now yes.
|
||||
|
||||
Q: How can you claim that you are anti-crack, while still
|
||||
writing a window manager?
|
||||
|
||||
A: I have no comment on that.
|
51
configure.ac
51
configure.ac
@ -17,10 +17,14 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR(src/core/display.c)
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar])
|
||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar 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 +40,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])
|
||||
|
||||
@ -75,7 +79,7 @@ MUTTER_PC_MODULES="
|
||||
cairo >= 1.10.0
|
||||
gsettings-desktop-schemas >= 3.7.3
|
||||
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
|
||||
$CLUTTER_PACKAGE >= 1.15.90
|
||||
$CLUTTER_PACKAGE >= 1.17.5
|
||||
cogl-1.0 >= 1.17.1
|
||||
upower-glib >= 0.99.0
|
||||
gnome-desktop-3.0
|
||||
@ -117,11 +121,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"])
|
||||
|
||||
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"
|
||||
@ -186,20 +206,15 @@ if test x$found_introspection != xno; then
|
||||
AC_SUBST(META_GIR)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([Xcursor])
|
||||
if $PKG_CONFIG xcursor; then
|
||||
have_xcursor=yes
|
||||
else
|
||||
have_xcursor=no
|
||||
fi
|
||||
AC_MSG_RESULT($have_xcursor)
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
|
||||
|
||||
if test x$have_xcursor = xyes; then
|
||||
echo "Building with Xcursor"
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
|
||||
AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support])
|
||||
fi
|
||||
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
|
||||
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
||||
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
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],
|
||||
@ -437,8 +452,7 @@ doc/man/Makefile
|
||||
doc/reference/Makefile
|
||||
doc/reference/meta-docs.sgml
|
||||
src/Makefile
|
||||
src/libmutter.pc
|
||||
src/mutter-plugins.pc
|
||||
src/libmutter-wayland.pc
|
||||
src/compositor/plugins/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
@ -455,7 +469,7 @@ fi
|
||||
|
||||
dnl ==========================================================================
|
||||
echo "
|
||||
mutter-$VERSION
|
||||
mutter-wayland-$VERSION
|
||||
|
||||
prefix: ${prefix}
|
||||
source code location: ${srcdir}
|
||||
@ -467,7 +481,6 @@ mutter-$VERSION
|
||||
Session management: ${found_sm}
|
||||
Shape extension: ${found_shape}
|
||||
Xsync: ${found_xsync}
|
||||
Xcursor: ${have_xcursor}
|
||||
"
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS = man reference
|
||||
|
||||
EXTRA_DIST=theme-format.txt dialogs.txt code-overview.txt \
|
||||
how-to-get-focus-right.txt
|
||||
how-to-get-focus-right.txt rationales.txt
|
||||
|
@ -140,7 +140,7 @@ expand_content_files= \
|
||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||
GTKDOC_CFLAGS=$(MUTTER_CFLAGS)
|
||||
GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter.la
|
||||
GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter-wayland.la
|
||||
|
||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
@ -16,14 +16,14 @@ src/core/monitor.c
|
||||
src/core/mutter.c
|
||||
src/core/prefs.c
|
||||
src/core/screen.c
|
||||
src/core/session.c
|
||||
src/x11/session.c
|
||||
src/core/util.c
|
||||
src/core/window.c
|
||||
src/core/window-props.c
|
||||
src/core/xprops.c
|
||||
src/mutter.desktop.in
|
||||
src/mutter-wm.desktop.in
|
||||
src/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
|
||||
|
228
src/Makefile.am
228
src/Makefile.am
@ -1,16 +1,19 @@
|
||||
# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905
|
||||
.AUTOPARALLEL:
|
||||
|
||||
lib_LTLIBRARIES = libmutter.la
|
||||
lib_LTLIBRARIES = libmutter-wayland.la
|
||||
|
||||
SUBDIRS=compositor/plugins
|
||||
|
||||
INCLUDES= \
|
||||
-DCLUTTER_ENABLE_COMPOSITOR_API \
|
||||
-DCLUTTER_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_API \
|
||||
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
|
||||
$(MUTTER_CFLAGS) \
|
||||
-I$(top_builddir) \
|
||||
-I$(srcdir) \
|
||||
-I$(srcdir)/backends \
|
||||
-I$(srcdir)/core \
|
||||
-I$(srcdir)/ui \
|
||||
-I$(srcdir)/compositor \
|
||||
@ -27,17 +30,56 @@ INCLUDES= \
|
||||
-DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) \
|
||||
-DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \
|
||||
-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \
|
||||
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
|
||||
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
|
||||
-DXWAYLAND_PATH='"@XWAYLAND_PATH@"'
|
||||
|
||||
mutter_built_sources = \
|
||||
$(dbus_idle_built_sources) \
|
||||
$(dbus_xrandr_built_sources) \
|
||||
mutter-enum-types.h \
|
||||
mutter-enum-types.c
|
||||
$(dbus_idle_built_sources) \
|
||||
$(dbus_display_config_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
|
||||
|
||||
libmutter_la_SOURCES = \
|
||||
core/async-getprop.c \
|
||||
core/async-getprop.h \
|
||||
wayland_protocols = \
|
||||
wayland/protocol/gtk-shell.xml \
|
||||
wayland/protocol/xdg-shell.xml
|
||||
|
||||
libmutter_wayland_la_SOURCES = \
|
||||
backends/meta-backend.c \
|
||||
backends/meta-backend.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-idle-monitor.c \
|
||||
backends/meta-idle-monitor-private.h \
|
||||
backends/meta-idle-monitor-dbus.c \
|
||||
backends/meta-idle-monitor-dbus.h \
|
||||
backends/meta-monitor-config.c \
|
||||
backends/meta-monitor-config.h \
|
||||
backends/meta-monitor-manager.c \
|
||||
backends/meta-monitor-manager.h \
|
||||
backends/meta-monitor-manager-dummy.c \
|
||||
backends/meta-monitor-manager-dummy.h \
|
||||
backends/edid-parse.c \
|
||||
backends/edid.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-weston-launch.c \
|
||||
backends/native/meta-weston-launch.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 \
|
||||
backends/x11/meta-xrandr-shared.h \
|
||||
core/meta-accel-parse.c \
|
||||
core/meta-accel-parse.h \
|
||||
core/barrier.c \
|
||||
meta/barrier.h \
|
||||
core/bell.c \
|
||||
@ -65,7 +107,13 @@ libmutter_la_SOURCES = \
|
||||
compositor/meta-shadow-factory.c \
|
||||
compositor/meta-shadow-factory-private.h \
|
||||
compositor/meta-shaped-texture.c \
|
||||
compositor/meta-shaped-texture-private.h \
|
||||
compositor/meta-shaped-texture-private.h \
|
||||
compositor/meta-surface-actor.c \
|
||||
compositor/meta-surface-actor.h \
|
||||
compositor/meta-surface-actor-x11.c \
|
||||
compositor/meta-surface-actor-x11.h \
|
||||
compositor/meta-surface-actor-wayland.c \
|
||||
compositor/meta-surface-actor-wayland.h \
|
||||
compositor/meta-texture-rectangle.c \
|
||||
compositor/meta-texture-rectangle.h \
|
||||
compositor/meta-texture-tower.c \
|
||||
@ -86,7 +134,6 @@ libmutter_la_SOURCES = \
|
||||
meta/meta-shadow-factory.h \
|
||||
meta/meta-window-actor.h \
|
||||
meta/compositor-mutter.h \
|
||||
core/above-tab-keycode.c \
|
||||
core/constraints.c \
|
||||
core/constraints.h \
|
||||
core/core.c \
|
||||
@ -96,34 +143,17 @@ libmutter_la_SOURCES = \
|
||||
meta/display.h \
|
||||
core/edge-resistance.c \
|
||||
core/edge-resistance.h \
|
||||
core/edid-parse.c \
|
||||
core/edid.h \
|
||||
core/events.c \
|
||||
core/events.h \
|
||||
core/errors.c \
|
||||
meta/errors.h \
|
||||
core/frame.c \
|
||||
core/frame.h \
|
||||
ui/gradient.c \
|
||||
meta/gradient.h \
|
||||
core/group-private.h \
|
||||
core/group-props.c \
|
||||
core/group-props.h \
|
||||
core/group.c \
|
||||
meta/group.h \
|
||||
core/iconcache.c \
|
||||
core/iconcache.h \
|
||||
core/keybindings.c \
|
||||
core/keybindings-private.h \
|
||||
core/main.c \
|
||||
core/meta-cursor-tracker.c \
|
||||
core/meta-cursor-tracker-private.h \
|
||||
core/meta-idle-monitor.c \
|
||||
core/meta-idle-monitor-private.h \
|
||||
core/meta-xrandr-shared.h \
|
||||
core/monitor.c \
|
||||
core/monitor-config.c \
|
||||
core/monitor-private.h \
|
||||
core/monitor-xrandr.c \
|
||||
core/mutter-Xatomtype.h \
|
||||
core/place.c \
|
||||
core/place.h \
|
||||
core/prefs.c \
|
||||
@ -132,8 +162,6 @@ libmutter_la_SOURCES = \
|
||||
core/screen-private.h \
|
||||
meta/screen.h \
|
||||
meta/types.h \
|
||||
core/session.c \
|
||||
core/session.h \
|
||||
core/stack.c \
|
||||
core/stack.h \
|
||||
core/stack-tracker.c \
|
||||
@ -141,15 +169,11 @@ libmutter_la_SOURCES = \
|
||||
core/util.c \
|
||||
meta/util.h \
|
||||
core/util-private.h \
|
||||
core/window-props.c \
|
||||
core/window-props.h \
|
||||
core/window.c \
|
||||
core/window-private.h \
|
||||
meta/window.h \
|
||||
core/workspace.c \
|
||||
core/workspace-private.h \
|
||||
core/xprops.c \
|
||||
core/xprops.h \
|
||||
meta/common.h \
|
||||
core/core.h \
|
||||
ui/ui.h \
|
||||
@ -165,13 +189,54 @@ libmutter_la_SOURCES = \
|
||||
ui/theme.c \
|
||||
meta/theme.h \
|
||||
ui/theme-private.h \
|
||||
ui/ui.c
|
||||
ui/ui.c \
|
||||
x11/iconcache.c \
|
||||
x11/iconcache.h \
|
||||
x11/async-getprop.c \
|
||||
x11/async-getprop.h \
|
||||
x11/group-private.h \
|
||||
x11/group-props.c \
|
||||
x11/group-props.h \
|
||||
x11/group.c \
|
||||
meta/group.h \
|
||||
x11/session.c \
|
||||
x11/session.h \
|
||||
x11/window-props.c \
|
||||
x11/window-props.h \
|
||||
x11/window-x11.c \
|
||||
x11/window-x11.h \
|
||||
x11/window-x11-private.h \
|
||||
x11/xprops.c \
|
||||
x11/xprops.h \
|
||||
x11/mutter-Xatomtype.h \
|
||||
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-wayland-data-device.c \
|
||||
wayland/meta-wayland-data-device.h \
|
||||
wayland/meta-wayland-keyboard.c \
|
||||
wayland/meta-wayland-keyboard.h \
|
||||
wayland/meta-wayland-pointer.c \
|
||||
wayland/meta-wayland-pointer.h \
|
||||
wayland/meta-wayland-seat.c \
|
||||
wayland/meta-wayland-seat.h \
|
||||
wayland/meta-wayland-stage.h \
|
||||
wayland/meta-wayland-stage.c \
|
||||
wayland/meta-wayland-surface.c \
|
||||
wayland/meta-wayland-surface.h \
|
||||
wayland/meta-wayland-types.h \
|
||||
wayland/meta-wayland-versions.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
|
||||
@ -209,16 +274,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)
|
||||
@ -240,41 +318,36 @@ typelib_DATA = Meta-$(api_version).typelib
|
||||
|
||||
INTROSPECTION_GIRS = Meta-$(api_version).gir
|
||||
|
||||
Meta-$(api_version).gir: libmutter.la
|
||||
Meta-$(api_version).gir: libmutter-wayland.la
|
||||
@META_GIR@_INCLUDES = GObject-2.0 GDesktopEnums-3.0 Gdk-3.0 Gtk-3.0 Clutter-1.0 xlib-2.0 xfixes-4.0 Cogl-1.0
|
||||
@META_GIR@_EXPORT_PACKAGES = libmutter
|
||||
@META_GIR@_EXPORT_PACKAGES = libmutter-wayland
|
||||
@META_GIR@_CFLAGS = $(INCLUDES)
|
||||
@META_GIR@_LIBS = libmutter.la
|
||||
@META_GIR@_LIBS = libmutter-wayland.la
|
||||
@META_GIR@_FILES = \
|
||||
mutter-enum-types.h \
|
||||
$(libmutterinclude_base_headers) \
|
||||
$(filter %.c,$(libmutter_la_SOURCES) $(nodist_libmutter_la_SOURCES))
|
||||
$(filter %.c,$(libmutter_wayland_la_SOURCES) $(nodist_libmutter_wayland_la_SOURCES))
|
||||
@META_GIR@_SCANNERFLAGS = --warn-all --warn-error
|
||||
|
||||
endif
|
||||
|
||||
testboxes_SOURCES = core/testboxes.c
|
||||
testgradient_SOURCES = ui/testgradient.c
|
||||
testasyncgetprop_SOURCES = core/testasyncgetprop.c
|
||||
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
|
||||
|
||||
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
|
||||
|
||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
|
||||
testboxes_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
testgradient_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
|
||||
@INTLTOOL_DESKTOP_RULE@
|
||||
|
||||
desktopfilesdir=$(datadir)/applications
|
||||
desktopfiles_in_files=mutter.desktop.in
|
||||
desktopfiles_in_files=mutter-wayland.desktop.in
|
||||
desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop)
|
||||
desktopfiles_DATA = $(desktopfiles_files)
|
||||
|
||||
wmpropertiesdir=$(datadir)/gnome/wm-properties
|
||||
wmproperties_in_files=mutter-wm.desktop.in
|
||||
wmproperties_files=$(wmproperties_in_files:.desktop.in=.desktop)
|
||||
wmproperties_DATA = $(wmproperties_files)
|
||||
|
||||
xmldir = @GNOME_KEYBINDINGS_KEYSDIR@
|
||||
xml_in_files = \
|
||||
50-mutter-navigation.xml.in \
|
||||
@ -282,7 +355,9 @@ xml_in_files = \
|
||||
50-mutter-windows.xml.in
|
||||
xml_DATA = $(xml_in_files:.xml.in=.xml)
|
||||
|
||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
|
||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||
|
||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml
|
||||
@INTLTOOL_XML_NOMERGE_RULE@
|
||||
@GSETTINGS_RULES@
|
||||
|
||||
@ -290,9 +365,10 @@ 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 \
|
||||
$(xml_DATA) \
|
||||
$(mutter_built_sources) \
|
||||
$(typelib_DATA) \
|
||||
@ -300,7 +376,7 @@ CLEANFILES = \
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
pkgconfig_DATA = libmutter.pc mutter-plugins.pc
|
||||
pkgconfig_DATA = libmutter-wayland.pc
|
||||
|
||||
EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(wmproperties_files) \
|
||||
@ -308,14 +384,15 @@ EXTRA_DIST=$(desktopfiles_files) \
|
||||
$(desktopfiles_in_files) \
|
||||
$(wmproperties_in_files) \
|
||||
$(xml_in_files) \
|
||||
$(wayland_protocols) \
|
||||
org.gnome.mutter.gschema.xml.in \
|
||||
idle-monitor.xml \
|
||||
xrandr.xml \
|
||||
org.gnome.mutter.wayland.gschema.xml.in \
|
||||
mutter-schemas.convert \
|
||||
libmutter.pc.in \
|
||||
mutter-plugins.pc.in \
|
||||
libmutter-wayland.pc.in \
|
||||
mutter-enum-types.h.in \
|
||||
mutter-enum-types.c.in
|
||||
mutter-enum-types.c.in \
|
||||
org.gnome.Mutter.DisplayConfig.xml \
|
||||
org.gnome.Mutter.IdleMonitor.xml
|
||||
|
||||
BUILT_SOURCES = $(mutter_built_sources)
|
||||
MUTTER_STAMP_FILES = stamp-mutter-enum-types.h
|
||||
@ -340,21 +417,24 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in
|
||||
cp xgen-tetc mutter-enum-types.c && \
|
||||
rm -f xgen-tetc
|
||||
|
||||
dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
|
||||
dbus_display_config_built_sources = meta-dbus-display-config.c meta-dbus-display-config.h
|
||||
|
||||
$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
|
||||
$(dbus_display_config_built_sources) : Makefile.am org.gnome.Mutter.DisplayConfig.xml
|
||||
$(AM_V_GEN)gdbus-codegen \
|
||||
--interface-prefix org.gnome.Mutter \
|
||||
--c-namespace MetaDBus \
|
||||
--generate-c-code meta-dbus-xrandr \
|
||||
$(srcdir)/xrandr.xml
|
||||
--generate-c-code meta-dbus-display-config \
|
||||
$(srcdir)/org.gnome.Mutter.DisplayConfig.xml
|
||||
|
||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||
|
||||
$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
|
||||
$(dbus_idle_built_sources) : Makefile.am org.gnome.Mutter.IdleMonitor.xml
|
||||
$(AM_V_GEN)gdbus-codegen \
|
||||
--interface-prefix org.gnome.Mutter \
|
||||
--c-namespace MetaDBus \
|
||||
--generate-c-code meta-dbus-idle-monitor \
|
||||
--c-generate-object-manager \
|
||||
$(srcdir)/idle-monitor.xml
|
||||
$(srcdir)/org.gnome.Mutter.IdleMonitor.xml
|
||||
|
||||
%-protocol.c : $(srcdir)/wayland/protocol/%.xml
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
|
||||
%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
|
||||
|
157
src/backends/meta-backend.c
Normal file
157
src/backends/meta-backend.c
Normal file
@ -0,0 +1,157 @@
|
||||
/* -*- 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.h"
|
||||
#include <meta/main.h>
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
|
||||
#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
|
||||
* the X fd, but we do have to deal with dispatching events that accumulate
|
||||
* in the clutter queue. This happens, for example, when clutter generate
|
||||
* enter/leave events on mouse motion - several events are queued in the
|
||||
* clutter queue but only one dispatched. It could also happen because of
|
||||
* explicit calls to clutter_event_put(). We add a very simple custom
|
||||
* event loop source which is simply responsible for pulling events off
|
||||
* of the queue and dispatching them before we block for new events.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
event_prepare (GSource *source,
|
||||
gint *timeout_)
|
||||
{
|
||||
*timeout_ = -1;
|
||||
|
||||
return clutter_events_pending ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_check (GSource *source)
|
||||
{
|
||||
return clutter_events_pending ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterEvent *event = clutter_event_get ();
|
||||
|
||||
if (event)
|
||||
{
|
||||
clutter_do_event (event);
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs event_funcs = {
|
||||
event_prepare,
|
||||
event_check,
|
||||
event_dispatch
|
||||
};
|
||||
|
||||
static MetaLauncher *launcher;
|
||||
|
||||
void
|
||||
meta_clutter_init (void)
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
/* 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");
|
||||
|
||||
source = g_source_new (&event_funcs, sizeof (GSource));
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
34
src/backends/meta-backend.h
Normal file
34
src/backends/meta-backend.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* -*- 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_H
|
||||
#define META_BACKEND_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
void meta_clutter_init (void);
|
||||
|
||||
gboolean meta_activate_vt (int vt, GError **error);
|
||||
|
||||
#endif /* META_BACKEND_H */
|
50
src/backends/meta-cursor-private.h
Normal file
50
src/backends/meta-cursor-private.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef META_CURSOR_PRIVATE_H
|
||||
#define META_CURSOR_PRIVATE_H
|
||||
|
||||
#include "meta-cursor.h"
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <gbm.h>
|
||||
|
||||
typedef struct {
|
||||
CoglTexture2D *texture;
|
||||
struct gbm_bo *bo;
|
||||
int hot_x, hot_y;
|
||||
} MetaCursorImage;
|
||||
|
||||
struct _MetaCursorReference {
|
||||
int ref_count;
|
||||
|
||||
MetaCursorImage image;
|
||||
};
|
||||
|
||||
CoglTexture *meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
|
||||
int *hot_x,
|
||||
int *hot_y);
|
||||
|
||||
struct gbm_bo *meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
||||
int *hot_x,
|
||||
int *hot_y);
|
||||
|
||||
#endif /* META_CURSOR_PRIVATE_H */
|
98
src/backends/meta-cursor-tracker-private.h
Normal file
98
src/backends/meta-cursor-tracker-private.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef META_CURSOR_TRACKER_PRIVATE_H
|
||||
#define META_CURSOR_TRACKER_PRIVATE_H
|
||||
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include "meta-cursor.h"
|
||||
|
||||
struct _MetaCursorTracker {
|
||||
GObject parent_instance;
|
||||
|
||||
MetaScreen *screen;
|
||||
|
||||
gboolean is_showing;
|
||||
gboolean has_hw_cursor;
|
||||
|
||||
/* 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;
|
||||
|
||||
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
|
||||
* determine an unset window cursor; we need an extra boolean.
|
||||
*/
|
||||
gboolean has_window_cursor;
|
||||
MetaCursorReference *window_cursor;
|
||||
|
||||
MetaCursorReference *root_cursor;
|
||||
|
||||
MetaCursorReference *theme_cursors[META_CURSOR_LAST];
|
||||
|
||||
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 _MetaCursorTrackerClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||
XEvent *xevent);
|
||||
|
||||
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);
|
||||
void meta_cursor_tracker_paint (MetaCursorTracker *tracker);
|
||||
|
||||
void meta_cursor_tracker_force_update (MetaCursorTracker *tracker);
|
||||
|
||||
#endif
|
738
src/backends/meta-cursor-tracker.c
Normal file
738
src/backends/meta-cursor-tracker.c
Normal file
@ -0,0 +1,738 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:cursor-tracker
|
||||
* @title: MetaCursorTracker
|
||||
* @short_description: Mutter cursor tracking helper. Originally only
|
||||
* tracking the cursor image, now more of a "core
|
||||
* pointer abstraction"
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/util.h>
|
||||
#include <meta/errors.h>
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <gbm.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include "meta-cursor-private.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "screen-private.h"
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
|
||||
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
CURSOR_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
|
||||
MetaCRTC *crtc,
|
||||
gboolean has_hw_cursor);
|
||||
static void sync_cursor (MetaCursorTracker *tracker);
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_init (MetaCursorTracker *self)
|
||||
{
|
||||
/* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of
|
||||
detecting if the system mouse cursor is showing or not.
|
||||
|
||||
On wayland we start with the cursor showing
|
||||
*/
|
||||
self->is_showing = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_finalize (GObject *object)
|
||||
{
|
||||
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
|
||||
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]);
|
||||
|
||||
if (self->pipeline)
|
||||
cogl_object_unref (self->pipeline);
|
||||
if (self->gbm)
|
||||
gbm_device_destroy (self->gbm);
|
||||
|
||||
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_cursor_tracker_finalize;
|
||||
|
||||
signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_monitors_changed (MetaMonitorManager *monitors,
|
||||
MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaCRTC *crtcs;
|
||||
unsigned int i, n_crtcs;
|
||||
|
||||
if (!tracker->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 (&tracker->current_rect, rect);
|
||||
|
||||
/* Need to do it unconditionally here, our tracking is
|
||||
wrong because we reloaded the CRTCs */
|
||||
meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
|
||||
}
|
||||
}
|
||||
|
||||
static MetaCursorTracker *
|
||||
make_wayland_cursor_tracker (MetaScreen *screen)
|
||||
{
|
||||
MetaWaylandCompositor *compositor;
|
||||
CoglContext *ctx;
|
||||
MetaMonitorManager *monitors;
|
||||
MetaCursorTracker *self;
|
||||
|
||||
self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
self->pipeline = cogl_pipeline_new (ctx);
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
compositor->seat->cursor_tracker = self;
|
||||
meta_cursor_tracker_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);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static MetaCursorTracker *
|
||||
make_x11_cursor_tracker (MetaScreen *screen)
|
||||
{
|
||||
MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
|
||||
XFixesSelectCursorInput (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
XFixesDisplayCursorNotifyMask);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_for_screen:
|
||||
* @screen: the #MetaScreen
|
||||
*
|
||||
* Retrieves the cursor tracker object for @screen.
|
||||
*
|
||||
* Returns: (transfer none):
|
||||
*/
|
||||
MetaCursorTracker *
|
||||
meta_cursor_tracker_get_for_screen (MetaScreen *screen)
|
||||
{
|
||||
MetaCursorTracker *self;
|
||||
|
||||
if (screen->cursor_tracker)
|
||||
return screen->cursor_tracker;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
self = make_wayland_cursor_tracker (screen);
|
||||
else
|
||||
self = make_x11_cursor_tracker (screen);
|
||||
|
||||
screen->cursor_tracker = self;
|
||||
return self;
|
||||
}
|
||||
|
||||
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 (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;
|
||||
|
||||
set_window_cursor (tracker, FALSE, NULL);
|
||||
|
||||
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->has_window_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;
|
||||
}
|
||||
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);
|
||||
|
||||
if (sprite != NULL)
|
||||
{
|
||||
MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite,
|
||||
cursor_image->xhot,
|
||||
cursor_image->yhot);
|
||||
set_window_cursor (tracker, TRUE, cursor);
|
||||
}
|
||||
XFree (cursor_image);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_sprite:
|
||||
*
|
||||
* Returns: (transfer none):
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
ensure_xfixes_cursor (tracker);
|
||||
|
||||
if (tracker->displayed_cursor)
|
||||
return meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_hot:
|
||||
* @tracker:
|
||||
* @x: (out):
|
||||
* @y: (out):
|
||||
*
|
||||
*/
|
||||
void
|
||||
meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
||||
int *x,
|
||||
int *y)
|
||||
{
|
||||
g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
ensure_xfixes_cursor (tracker);
|
||||
|
||||
if (tracker->displayed_cursor)
|
||||
meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, x, y);
|
||||
else
|
||||
{
|
||||
if (x)
|
||||
*x = 0;
|
||||
if (y)
|
||||
*y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
sync_cursor (tracker);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
|
||||
MetaCursorReference *cursor)
|
||||
{
|
||||
set_window_cursor (tracker, TRUE, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
set_window_cursor (tracker, FALSE, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||
MetaCursorReference *cursor)
|
||||
{
|
||||
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
|
||||
if (cursor)
|
||||
tracker->root_cursor = meta_cursor_reference_ref (cursor);
|
||||
|
||||
sync_cursor (tracker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_have_hw_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
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 (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaMonitorManager *monitors;
|
||||
MetaCRTC *crtcs;
|
||||
unsigned int i, n_crtcs;
|
||||
gboolean enabled;
|
||||
|
||||
enabled = should_have_hw_cursor (tracker);
|
||||
tracker->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 (&tracker->current_rect, rect);
|
||||
|
||||
if (has || crtcs[i].has_hw_cursor)
|
||||
meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
move_hw_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
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 (tracker->has_hw_cursor);
|
||||
|
||||
for (i = 0; i < n_crtcs; i++)
|
||||
{
|
||||
MetaRectangle *rect = &crtcs[i].rect;
|
||||
gboolean has;
|
||||
|
||||
has = meta_rectangle_overlap (&tracker->current_rect, rect);
|
||||
|
||||
if (has != crtcs[i].has_hw_cursor)
|
||||
meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
|
||||
if (has)
|
||||
drmModeMoveCursor (tracker->drm_fd, crtcs[i].crtc_id,
|
||||
tracker->current_rect.x - rect->x,
|
||||
tracker->current_rect.y - rect->y);
|
||||
}
|
||||
}
|
||||
|
||||
static MetaCursorReference *
|
||||
get_displayed_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
if (!tracker->is_showing)
|
||||
return NULL;
|
||||
|
||||
if (tracker->grab_cursor)
|
||||
return tracker->grab_cursor;
|
||||
|
||||
if (tracker->has_window_cursor)
|
||||
return tracker->window_cursor;
|
||||
|
||||
return tracker->root_cursor;
|
||||
}
|
||||
|
||||
static void
|
||||
update_displayed_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
if (tracker->displayed_cursor)
|
||||
{
|
||||
CoglTexture *texture = meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL);
|
||||
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, texture);
|
||||
}
|
||||
else
|
||||
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
|
||||
|
||||
update_hw_cursor (tracker);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_displayed_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_queue_redraw (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
ClutterActor *stage = compositor->stage;
|
||||
cairo_rectangle_int_t clip;
|
||||
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
/* Clear the location the cursor was at before, if we need to. */
|
||||
if (tracker->previous_is_valid)
|
||||
{
|
||||
clip.x = tracker->previous_rect.x;
|
||||
clip.y = tracker->previous_rect.y;
|
||||
clip.width = tracker->previous_rect.width;
|
||||
clip.height = tracker->previous_rect.height;
|
||||
clutter_actor_queue_redraw_with_clip (stage, &clip);
|
||||
tracker->previous_is_valid = FALSE;
|
||||
}
|
||||
|
||||
if (tracker->has_hw_cursor || !tracker->displayed_cursor)
|
||||
return;
|
||||
|
||||
clip.x = tracker->current_rect.x;
|
||||
clip.y = tracker->current_rect.y;
|
||||
clip.width = tracker->current_rect.width;
|
||||
clip.height = tracker->current_rect.height;
|
||||
clutter_actor_queue_redraw_with_clip (stage, &clip);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaCursorReference *displayed_cursor;
|
||||
|
||||
sync_displayed_cursor (tracker);
|
||||
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);
|
||||
|
||||
tracker->current_rect.x = tracker->current_x - hot_x;
|
||||
tracker->current_rect.y = tracker->current_y - hot_y;
|
||||
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
|
||||
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
tracker->current_rect.x = 0;
|
||||
tracker->current_rect.y = 0;
|
||||
tracker->current_rect.width = 0;
|
||||
tracker->current_rect.height = 0;
|
||||
}
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
if (tracker->has_hw_cursor)
|
||||
move_hw_cursor (tracker);
|
||||
else
|
||||
meta_cursor_tracker_queue_redraw (tracker);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
|
||||
int new_x,
|
||||
int new_y)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
tracker->current_x = new_x;
|
||||
tracker->current_y = new_y;
|
||||
|
||||
sync_cursor (tracker);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_paint (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
if (tracker->has_hw_cursor || !tracker->displayed_cursor)
|
||||
return;
|
||||
|
||||
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
|
||||
tracker->pipeline,
|
||||
tracker->current_rect.x,
|
||||
tracker->current_rect.y,
|
||||
tracker->current_rect.x +
|
||||
tracker->current_rect.width,
|
||||
tracker->current_rect.y +
|
||||
tracker->current_rect.height);
|
||||
|
||||
tracker->previous_rect = tracker->current_rect;
|
||||
tracker->previous_is_valid = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
|
||||
MetaCRTC *crtc,
|
||||
gboolean has)
|
||||
{
|
||||
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 (tracker->drm_fd, crtc->crtc_id, handle.u32,
|
||||
width, height, hot_x, hot_y);
|
||||
crtc->has_hw_cursor = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
|
||||
crtc->has_hw_cursor = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_pointer_position_gdk (int *x,
|
||||
int *y,
|
||||
int *mods)
|
||||
{
|
||||
GdkDeviceManager *gmanager;
|
||||
GdkDevice *gdevice;
|
||||
GdkScreen *gscreen;
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
|
||||
int *x,
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
|
||||
gboolean visible)
|
||||
{
|
||||
if (visible == tracker->is_showing)
|
||||
return;
|
||||
tracker->is_showing = visible;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
sync_cursor (tracker);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (visible)
|
||||
XFixesShowCursor (tracker->screen->display->xdisplay,
|
||||
tracker->screen->xroot);
|
||||
else
|
||||
XFixesHideCursor (tracker->screen->display->xdisplay,
|
||||
tracker->screen->xroot);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_force_update (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
update_hw_cursor (tracker);
|
||||
sync_cursor (tracker);
|
||||
}
|
412
src/backends/meta-cursor.c
Normal file
412
src/backends/meta-cursor.c
Normal file
@ -0,0 +1,412 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-cursor-private.h"
|
||||
|
||||
#include <meta/errors.h>
|
||||
|
||||
#include "display-private.h"
|
||||
#include "screen-private.h"
|
||||
#include "meta-cursor-tracker-private.h" /* for tracker->gbm */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
|
||||
MetaCursorReference *
|
||||
meta_cursor_reference_ref (MetaCursorReference *self)
|
||||
{
|
||||
g_assert (self->ref_count > 0);
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_image_free (MetaCursorImage *image)
|
||||
{
|
||||
cogl_object_unref (image->texture);
|
||||
if (image->bo)
|
||||
gbm_bo_destroy (image->bo);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_reference_free (MetaCursorReference *self)
|
||||
{
|
||||
meta_cursor_image_free (&self->image);
|
||||
g_slice_free (MetaCursorReference, self);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_reference_unref (MetaCursorReference *self)
|
||||
{
|
||||
self->ref_count--;
|
||||
|
||||
if (self->ref_count == 0)
|
||||
meta_cursor_reference_free (self);
|
||||
}
|
||||
|
||||
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:
|
||||
glyph = XC_left_ptr;
|
||||
break;
|
||||
case META_CURSOR_NORTH_RESIZE:
|
||||
glyph = XC_top_side;
|
||||
break;
|
||||
case META_CURSOR_SOUTH_RESIZE:
|
||||
glyph = XC_bottom_side;
|
||||
break;
|
||||
case META_CURSOR_WEST_RESIZE:
|
||||
glyph = XC_left_side;
|
||||
break;
|
||||
case META_CURSOR_EAST_RESIZE:
|
||||
glyph = XC_right_side;
|
||||
break;
|
||||
case META_CURSOR_SE_RESIZE:
|
||||
glyph = XC_bottom_right_corner;
|
||||
break;
|
||||
case META_CURSOR_SW_RESIZE:
|
||||
glyph = XC_bottom_left_corner;
|
||||
break;
|
||||
case META_CURSOR_NE_RESIZE:
|
||||
glyph = XC_top_right_corner;
|
||||
break;
|
||||
case META_CURSOR_NW_RESIZE:
|
||||
glyph = XC_top_left_corner;
|
||||
break;
|
||||
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
|
||||
glyph = XC_fleur;
|
||||
break;
|
||||
case META_CURSOR_BUSY:
|
||||
glyph = XC_watch;
|
||||
break;
|
||||
case META_CURSOR_DND_IN_DRAG:
|
||||
name = "dnd-none";
|
||||
break;
|
||||
case META_CURSOR_DND_MOVE:
|
||||
name = "dnd-move";
|
||||
break;
|
||||
case META_CURSOR_DND_COPY:
|
||||
name = "dnd-copy";
|
||||
break;
|
||||
case META_CURSOR_DND_UNSUPPORTED_TARGET:
|
||||
name = "dnd-none";
|
||||
break;
|
||||
case META_CURSOR_POINTING_HAND:
|
||||
glyph = XC_hand2;
|
||||
break;
|
||||
case META_CURSOR_CROSSHAIR:
|
||||
glyph = XC_crosshair;
|
||||
break;
|
||||
case META_CURSOR_IBEAM:
|
||||
glyph = XC_xterm;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
glyph = 0; /* silence compiler */
|
||||
break;
|
||||
}
|
||||
|
||||
*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_display_create_x_cursor (MetaDisplay *display,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
return load_cursor_on_server (display, cursor);
|
||||
}
|
||||
|
||||
static XcursorImage *
|
||||
load_cursor_on_client (MetaDisplay *display,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (width > 64 || height > 64)
|
||||
{
|
||||
meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gbm_device_is_format_supported (gbm, gbm_format,
|
||||
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_image_load_from_xcursor_image (MetaCursorTracker *tracker,
|
||||
MetaCursorImage *image,
|
||||
XcursorImage *xc_image)
|
||||
{
|
||||
int width, height, rowstride;
|
||||
CoglPixelFormat cogl_format;
|
||||
uint32_t gbm_format;
|
||||
ClutterBackend *clutter_backend;
|
||||
CoglContext *cogl_context;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
if (tracker->gbm)
|
||||
meta_cursor_image_load_gbm_buffer (tracker->gbm,
|
||||
image,
|
||||
(uint8_t *) xc_image->pixels,
|
||||
width, height, rowstride,
|
||||
gbm_format);
|
||||
}
|
||||
|
||||
MetaCursorReference *
|
||||
meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
MetaCursorReference *self;
|
||||
XcursorImage *image;
|
||||
|
||||
if (tracker->theme_cursors[cursor])
|
||||
return meta_cursor_reference_ref (tracker->theme_cursors[cursor]);
|
||||
|
||||
image = load_cursor_on_client (tracker->screen->display, cursor);
|
||||
if (!image)
|
||||
return NULL;
|
||||
|
||||
self = g_slice_new0 (MetaCursorReference);
|
||||
self->ref_count = 1;
|
||||
meta_cursor_image_load_from_xcursor_image (tracker, &self->image, image);
|
||||
|
||||
XcursorImageDestroy (image);
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_image_load_from_buffer (MetaCursorTracker *tracker,
|
||||
MetaCursorImage *image,
|
||||
struct wl_resource *buffer,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
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 (tracker->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 (tracker->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 (tracker->gbm)
|
||||
{
|
||||
image->bo = gbm_bo_import (tracker->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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetaCursorReference *
|
||||
meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
|
||||
struct wl_resource *buffer,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
MetaCursorReference *self;
|
||||
|
||||
self = g_slice_new0 (MetaCursorReference);
|
||||
self->ref_count = 1;
|
||||
meta_cursor_image_load_from_buffer (tracker, &self->image, buffer, hot_x, hot_y);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
CoglTexture *
|
||||
meta_cursor_reference_get_cogl_texture (MetaCursorReference *cursor,
|
||||
int *hot_x,
|
||||
int *hot_y)
|
||||
{
|
||||
if (hot_x)
|
||||
*hot_x = cursor->image.hot_x;
|
||||
if (hot_y)
|
||||
*hot_y = cursor->image.hot_y;
|
||||
return COGL_TEXTURE (cursor->image.texture);
|
||||
}
|
||||
|
||||
struct gbm_bo *
|
||||
meta_cursor_reference_get_gbm_bo (MetaCursorReference *cursor,
|
||||
int *hot_x,
|
||||
int *hot_y)
|
||||
{
|
||||
if (hot_x)
|
||||
*hot_x = cursor->image.hot_x;
|
||||
if (hot_y)
|
||||
*hot_y = cursor->image.hot_y;
|
||||
return cursor->image.bo;
|
||||
}
|
42
src/backends/meta-cursor.h
Normal file
42
src/backends/meta-cursor.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef META_CURSOR_H
|
||||
#define META_CURSOR_H
|
||||
|
||||
typedef struct _MetaCursorReference MetaCursorReference;
|
||||
|
||||
MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor);
|
||||
void meta_cursor_reference_unref (MetaCursorReference *cursor);
|
||||
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
#include <meta/common.h>
|
||||
#include <wayland-server.h>
|
||||
|
||||
MetaCursorReference * meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
|
||||
MetaCursor cursor);
|
||||
|
||||
MetaCursorReference * meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
|
||||
struct wl_resource *buffer,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
|
||||
#endif /* META_CURSOR_H */
|
@ -16,7 +16,7 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file is shared between mutter (src/core/meta-xrandr-shared.h)
|
||||
/* This file is shared between mutter (src/core/meta-display-config-shared.h)
|
||||
and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h).
|
||||
|
||||
The canonical place for all changes is mutter.
|
||||
@ -24,8 +24,8 @@
|
||||
There should be no includes in this file.
|
||||
*/
|
||||
|
||||
#ifndef META_XRANDR_SHARED_H
|
||||
#define META_XRANDR_SHARED_H
|
||||
#ifndef META_DISPLAY_CONFIG_SHARED_H
|
||||
#define META_DISPLAY_CONFIG_SHARED_H
|
||||
|
||||
typedef enum {
|
||||
META_POWER_SAVE_UNSUPPORTED = -1,
|
||||
@ -35,4 +35,4 @@ typedef enum {
|
||||
META_POWER_SAVE_OFF,
|
||||
} MetaPowerSave;
|
||||
|
||||
#endif
|
||||
#endif /* META_DISPLAY_CONFIG_SHARED_H */
|
286
src/backends/meta-idle-monitor-dbus.c
Normal file
286
src/backends/meta-idle-monitor-dbus.c
Normal file
@ -0,0 +1,286 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-idle-monitor-dbus.h"
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "meta-dbus-idle-monitor.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <meta/util.h>
|
||||
#include <meta/main.h> /* for meta_get_replace_current_wm () */
|
||||
|
||||
static gboolean
|
||||
handle_get_idletime (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
guint64 idletime;
|
||||
|
||||
idletime = meta_idle_monitor_get_idletime (monitor);
|
||||
meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaDBusIdleMonitor *dbus_monitor;
|
||||
MetaIdleMonitor *monitor;
|
||||
char *dbus_name;
|
||||
guint watch_id;
|
||||
guint name_watcher_id;
|
||||
} DBusWatch;
|
||||
|
||||
static void
|
||||
destroy_dbus_watch (gpointer data)
|
||||
{
|
||||
DBusWatch *watch = data;
|
||||
|
||||
g_object_unref (watch->dbus_monitor);
|
||||
g_object_unref (watch->monitor);
|
||||
g_free (watch->dbus_name);
|
||||
g_bus_unwatch_name (watch->name_watcher_id);
|
||||
|
||||
g_slice_free (DBusWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_idle_callback (MetaIdleMonitor *monitor,
|
||||
guint watch_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
DBusWatch *watch = user_data;
|
||||
GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor);
|
||||
|
||||
g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton),
|
||||
watch->dbus_name,
|
||||
g_dbus_interface_skeleton_get_object_path (skeleton),
|
||||
"org.gnome.Mutter.IdleMonitor",
|
||||
"WatchFired",
|
||||
g_variant_new ("(u)", watch_id),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
name_vanished_callback (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
DBusWatch *watch = user_data;
|
||||
|
||||
meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id);
|
||||
}
|
||||
|
||||
static DBusWatch *
|
||||
make_dbus_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = g_slice_new (DBusWatch);
|
||||
watch->dbus_monitor = g_object_ref (skeleton);
|
||||
watch->monitor = g_object_ref (monitor);
|
||||
watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
|
||||
watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
|
||||
watch->dbus_name,
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
NULL, /* appeared */
|
||||
name_vanished_callback,
|
||||
watch, NULL);
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_idle_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint64 interval,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = make_dbus_watch (skeleton, invocation, monitor);
|
||||
watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval,
|
||||
dbus_idle_callback, watch, destroy_dbus_watch);
|
||||
|
||||
meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = make_dbus_watch (skeleton, invocation, monitor);
|
||||
watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor,
|
||||
dbus_idle_callback, watch,
|
||||
destroy_dbus_watch);
|
||||
|
||||
meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_remove_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint id,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
meta_idle_monitor_remove_watch (monitor, id);
|
||||
meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
create_monitor_skeleton (GDBusObjectManagerServer *manager,
|
||||
MetaIdleMonitor *monitor,
|
||||
const char *path)
|
||||
{
|
||||
MetaDBusIdleMonitor *skeleton;
|
||||
MetaDBusObjectSkeleton *object;
|
||||
|
||||
skeleton = meta_dbus_idle_monitor_skeleton_new ();
|
||||
g_signal_connect_object (skeleton, "handle-add-idle-watch",
|
||||
G_CALLBACK (handle_add_idle_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-add-user-active-watch",
|
||||
G_CALLBACK (handle_add_user_active_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-remove-watch",
|
||||
G_CALLBACK (handle_remove_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-get-idletime",
|
||||
G_CALLBACK (handle_get_idletime), monitor, 0);
|
||||
|
||||
object = meta_dbus_object_skeleton_new (path);
|
||||
meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
|
||||
|
||||
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_added (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
GDBusObjectManagerServer *manager)
|
||||
{
|
||||
|
||||
MetaIdleMonitor *monitor;
|
||||
int device_id;
|
||||
char *path;
|
||||
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
monitor = meta_idle_monitor_get_for_device (device_id);
|
||||
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
|
||||
|
||||
create_monitor_skeleton (manager, monitor, path);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_removed (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
GDBusObjectManagerServer *manager)
|
||||
{
|
||||
int device_id;
|
||||
char *path;
|
||||
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
|
||||
g_dbus_object_manager_server_unexport (manager, path);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusObjectManagerServer *manager;
|
||||
ClutterDeviceManager *device_manager;
|
||||
MetaIdleMonitor *monitor;
|
||||
GSList *devices, *iter;
|
||||
char *path;
|
||||
|
||||
manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
|
||||
|
||||
/* We never clear the core monitor, as that's supposed to cumulate idle times from
|
||||
all devices */
|
||||
monitor = meta_idle_monitor_get_core ();
|
||||
path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
|
||||
create_monitor_skeleton (manager, monitor, path);
|
||||
g_free (path);
|
||||
|
||||
device_manager = clutter_device_manager_get_default ();
|
||||
devices = clutter_device_manager_list_devices (device_manager);
|
||||
|
||||
for (iter = devices; iter; iter = iter->next)
|
||||
on_device_added (device_manager, iter->data, manager);
|
||||
|
||||
g_slist_free (devices);
|
||||
|
||||
g_signal_connect_object (device_manager, "device-added",
|
||||
G_CALLBACK (on_device_added), manager, 0);
|
||||
g_signal_connect_object (device_manager, "device-removed",
|
||||
G_CALLBACK (on_device_removed), manager, 0);
|
||||
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_verbose ("Acquired name %s\n", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_verbose ("Lost or failed to acquire name %s\n", name);
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_init_dbus (void)
|
||||
{
|
||||
static int dbus_name_id;
|
||||
|
||||
if (dbus_name_id > 0)
|
||||
return;
|
||||
|
||||
dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gnome.Mutter.IdleMonitor",
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
||||
(meta_get_replace_current_wm () ?
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL, NULL);
|
||||
}
|
@ -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/>.
|
||||
*
|
||||
@ -20,9 +20,9 @@
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
|
||||
void meta_idle_monitor_handle_xevent_all (XEvent *xevent);
|
||||
|
||||
#ifndef META_IDLE_MONITOR_DBUS_H
|
||||
#define META_IDLE_MONITOR_DBUS_H
|
||||
|
||||
void meta_idle_monitor_init_dbus (void);
|
||||
|
||||
#endif
|
65
src/backends/meta-idle-monitor-private.h
Normal file
65
src/backends/meta-idle-monitor-private.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#ifndef META_IDLE_MONITOR_PRIVATE_H
|
||||
#define META_IDLE_MONITOR_PRIVATE_H
|
||||
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "display-private.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
guint id;
|
||||
MetaIdleMonitorWatchFunc callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
guint64 timeout_msec;
|
||||
int idle_source_id;
|
||||
} MetaIdleMonitorWatch;
|
||||
|
||||
struct _MetaIdleMonitor
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *watches;
|
||||
int device_id;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gint64 (*get_idletime) (MetaIdleMonitor *monitor);
|
||||
MetaIdleMonitorWatch * (*make_watch) (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
};
|
||||
|
||||
void _meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch);
|
||||
|
||||
#endif /* META_IDLE_MONITOR_PRIVATE_H */
|
367
src/backends/meta-idle-monitor.c
Normal file
367
src/backends/meta-idle-monitor.c
Normal file
@ -0,0 +1,367 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:idle-monitor
|
||||
* @title: MetaIdleMonitor
|
||||
* @short_description: Mutter idle counter (similar to X's IDLETIME)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
#include <meta/util.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-idle-monitor-dbus.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));
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DEVICE_ID,
|
||||
PROP_LAST,
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST];
|
||||
|
||||
G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT)
|
||||
|
||||
static MetaIdleMonitor *device_monitors[256];
|
||||
static int device_id_max;
|
||||
|
||||
void
|
||||
_meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
guint id;
|
||||
gboolean is_user_active_watch;
|
||||
|
||||
monitor = watch->monitor;
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
id = watch->id;
|
||||
is_user_active_watch = (watch->timeout_msec == 0);
|
||||
|
||||
if (watch->callback)
|
||||
watch->callback (monitor, id, watch->user_data);
|
||||
|
||||
if (is_user_active_watch)
|
||||
meta_idle_monitor_remove_watch (monitor, id);
|
||||
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_dispose (GObject *object)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
g_clear_pointer (&monitor->watches, g_hash_table_destroy);
|
||||
|
||||
G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE_ID:
|
||||
g_value_set_int (value, monitor->device_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE_ID:
|
||||
monitor->device_id = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_idle_monitor_dispose;
|
||||
object_class->get_property = meta_idle_monitor_get_property;
|
||||
object_class->set_property = meta_idle_monitor_set_property;
|
||||
|
||||
/**
|
||||
* MetaIdleMonitor:device_id:
|
||||
*
|
||||
* The device to listen to idletime on.
|
||||
*/
|
||||
obj_props[PROP_DEVICE_ID] =
|
||||
g_param_spec_int ("device-id",
|
||||
"Device ID",
|
||||
"The device to listen to idletime on",
|
||||
0, 255, 0,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_init (MetaIdleMonitor *monitor)
|
||||
{
|
||||
}
|
||||
|
||||
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:
|
||||
*
|
||||
* Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global
|
||||
* idletime for all devices. To track device-specific idletime,
|
||||
* use meta_idle_monitor_get_for_device().
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_idle_monitor_get_core (void)
|
||||
{
|
||||
ensure_device_monitor (0);
|
||||
return device_monitors[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_for_device:
|
||||
* @device_id: the device to get the idle time for.
|
||||
*
|
||||
* Returns: (transfer none): a new #MetaIdleMonitor that tracks the
|
||||
* device-specific idletime for @device. To track server-global idletime
|
||||
* for all devices, use meta_idle_monitor_get_core().
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_idle_monitor_get_for_device (int device_id)
|
||||
{
|
||||
g_return_val_if_fail (device_id > 0 && device_id < 256, NULL);
|
||||
|
||||
ensure_device_monitor (device_id);
|
||||
return device_monitors[device_id];
|
||||
}
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
watch = META_IDLE_MONITOR_GET_CLASS (monitor)->make_watch (monitor,
|
||||
timeout_msec,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
g_hash_table_insert (monitor->watches,
|
||||
GUINT_TO_POINTER (watch->id),
|
||||
watch);
|
||||
return watch;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_add_idle_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @interval_msec: The idletime interval, in milliseconds
|
||||
* @callback: (allow-none): The callback to call when the user has
|
||||
* accumulated @interval_msec milliseconds of idle time.
|
||||
* @user_data: (allow-none): The user data to pass to the callback
|
||||
* @notify: A #GDestroyNotify
|
||||
*
|
||||
* Returns: a watch id
|
||||
*
|
||||
* Adds a watch for a specific idle time. The callback will be called
|
||||
* when the user has accumulated @interval_msec milliseconds of idle time.
|
||||
* This function will return an ID that can either be passed to
|
||||
* meta_idle_monitor_remove_watch(), or can be used to tell idle time
|
||||
* watches apart if you have more than one.
|
||||
*
|
||||
* Also note that this function will only care about positive transitions
|
||||
* (user's idle time exceeding a certain time). If you want to know about
|
||||
* when the user has become active, use
|
||||
* meta_idle_monitor_add_user_active_watch().
|
||||
*/
|
||||
guint
|
||||
meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor,
|
||||
guint64 interval_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
|
||||
g_return_val_if_fail (interval_msec > 0, 0);
|
||||
|
||||
watch = make_watch (monitor,
|
||||
interval_msec,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_add_user_active_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @callback: (allow-none): The callback to call when the user is
|
||||
* active again.
|
||||
* @user_data: (allow-none): The user data to pass to the callback
|
||||
* @notify: A #GDestroyNotify
|
||||
*
|
||||
* Returns: a watch id
|
||||
*
|
||||
* Add a one-time watch to know when the user is active again.
|
||||
* Note that this watch is one-time and will de-activate after the
|
||||
* function is called, for efficiency purposes. It's most convenient
|
||||
* to call this when an idle watch, as added by
|
||||
* meta_idle_monitor_add_idle_watch(), has triggered.
|
||||
*/
|
||||
guint
|
||||
meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
|
||||
|
||||
watch = make_watch (monitor,
|
||||
0,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_remove_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @id: A watch ID
|
||||
*
|
||||
* Removes an idle time watcher, previously added by
|
||||
* meta_idle_monitor_add_idle_watch() or
|
||||
* meta_idle_monitor_add_user_active_watch().
|
||||
*/
|
||||
void
|
||||
meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
|
||||
guint id)
|
||||
{
|
||||
g_return_if_fail (META_IS_IDLE_MONITOR (monitor));
|
||||
|
||||
g_object_ref (monitor);
|
||||
g_hash_table_remove (monitor->watches,
|
||||
GUINT_TO_POINTER (id));
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_idletime:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
*
|
||||
* Returns: The current idle time, in milliseconds, or -1 for not supported
|
||||
*/
|
||||
gint64
|
||||
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
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);
|
||||
}
|
@ -34,13 +34,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-monitor-config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <libupower-glib/upower.h>
|
||||
|
||||
#include <meta/main.h>
|
||||
#include <meta/errors.h>
|
||||
#include "monitor-private.h"
|
||||
|
||||
/* These structures represent the intended/persistent configuration,
|
||||
as stored in the monitors.xml file.
|
55
src/backends/meta-monitor-config.h
Normal file
55
src/backends/meta-monitor-config.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_MONITOR_CONFIG_H
|
||||
#define META_MONITOR_CONFIG_H
|
||||
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
|
||||
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
|
||||
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||
#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
|
||||
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG))
|
||||
#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||
|
||||
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MetaMonitorConfig *meta_monitor_config_new (void);
|
||||
|
||||
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_monitor_config_make_default (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_monitor_config_update_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
|
||||
|
||||
void meta_monitor_config_restore_previous (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
#endif /* META_MONITOR_CONFIG_H */
|
227
src/backends/meta-monitor-manager-dummy.c
Normal file
227
src/backends/meta-monitor-manager-dummy.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* -*- 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,
|
||||
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-monitor-manager-dummy.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
struct _MetaMonitorManagerDummy
|
||||
{
|
||||
MetaMonitorManager parent_instance;
|
||||
};
|
||||
|
||||
struct _MetaMonitorManagerDummyClass
|
||||
{
|
||||
MetaMonitorManagerClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaMonitorManagerDummy, meta_monitor_manager_dummy, META_TYPE_MONITOR_MANAGER);
|
||||
|
||||
static void
|
||||
meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager)
|
||||
{
|
||||
manager->max_screen_width = 65535;
|
||||
manager->max_screen_height = 65535;
|
||||
manager->screen_width = 1024;
|
||||
manager->screen_height = 768;
|
||||
|
||||
manager->modes = g_new0 (MetaMonitorMode, 1);
|
||||
manager->n_modes = 1;
|
||||
|
||||
manager->modes[0].mode_id = 0;
|
||||
manager->modes[0].width = 1024;
|
||||
manager->modes[0].height = 768;
|
||||
manager->modes[0].refresh_rate = 60.0;
|
||||
|
||||
manager->crtcs = g_new0 (MetaCRTC, 1);
|
||||
manager->n_crtcs = 1;
|
||||
|
||||
manager->crtcs[0].crtc_id = 1;
|
||||
manager->crtcs[0].rect.x = 0;
|
||||
manager->crtcs[0].rect.y = 0;
|
||||
manager->crtcs[0].rect.width = manager->modes[0].width;
|
||||
manager->crtcs[0].rect.height = manager->modes[0].height;
|
||||
manager->crtcs[0].current_mode = &manager->modes[0];
|
||||
manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS;
|
||||
manager->crtcs[0].is_dirty = FALSE;
|
||||
manager->crtcs[0].logical_monitor = NULL;
|
||||
|
||||
manager->outputs = g_new0 (MetaOutput, 1);
|
||||
manager->n_outputs = 1;
|
||||
|
||||
manager->outputs[0].crtc = &manager->crtcs[0];
|
||||
manager->outputs[0].output_id = 1;
|
||||
manager->outputs[0].name = g_strdup ("LVDS");
|
||||
manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
|
||||
manager->outputs[0].product = g_strdup ("unknown");
|
||||
manager->outputs[0].serial = g_strdup ("0xC0FFEE");
|
||||
manager->outputs[0].width_mm = 222;
|
||||
manager->outputs[0].height_mm = 125;
|
||||
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
manager->outputs[0].preferred_mode = &manager->modes[0];
|
||||
manager->outputs[0].n_modes = 1;
|
||||
manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 1);
|
||||
manager->outputs[0].modes[0] = &manager->modes[0];
|
||||
manager->outputs[0].n_possible_crtcs = 1;
|
||||
manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 1);
|
||||
manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0];
|
||||
manager->outputs[0].n_possible_clones = 0;
|
||||
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0);
|
||||
manager->outputs[0].backlight = -1;
|
||||
manager->outputs[0].backlight_min = 0;
|
||||
manager->outputs[0].backlight_max = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_dummy_apply_config (MetaMonitorManager *manager,
|
||||
MetaCRTCInfo **crtcs,
|
||||
unsigned int n_crtcs,
|
||||
MetaOutputInfo **outputs,
|
||||
unsigned int n_outputs)
|
||||
{
|
||||
unsigned i;
|
||||
int screen_width = 0, screen_height = 0;
|
||||
|
||||
for (i = 0; i < n_crtcs; i++)
|
||||
{
|
||||
MetaCRTCInfo *crtc_info = crtcs[i];
|
||||
MetaCRTC *crtc = crtc_info->crtc;
|
||||
crtc->is_dirty = TRUE;
|
||||
|
||||
if (crtc_info->mode == NULL)
|
||||
{
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaMonitorMode *mode;
|
||||
MetaOutput *output;
|
||||
int i, n_outputs;
|
||||
int width, height;
|
||||
|
||||
mode = crtc_info->mode;
|
||||
|
||||
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
||||
{
|
||||
width = mode->height;
|
||||
height = mode->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = mode->width;
|
||||
height = mode->height;
|
||||
}
|
||||
|
||||
crtc->rect.x = crtc_info->x;
|
||||
crtc->rect.y = crtc_info->y;
|
||||
crtc->rect.width = width;
|
||||
crtc->rect.height = height;
|
||||
crtc->current_mode = mode;
|
||||
crtc->transform = crtc_info->transform;
|
||||
|
||||
screen_width = MAX (screen_width, crtc_info->x + width);
|
||||
screen_height = MAX (screen_height, crtc_info->y + height);
|
||||
|
||||
n_outputs = crtc_info->outputs->len;
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
output = ((MetaOutput**)crtc_info->outputs->pdata)[i];
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutputInfo *output_info = outputs[i];
|
||||
MetaOutput *output = output_info->output;
|
||||
|
||||
output->is_primary = output_info->is_primary;
|
||||
output->is_presentation = output_info->is_presentation;
|
||||
}
|
||||
|
||||
/* Disable CRTCs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_crtcs; i++)
|
||||
{
|
||||
MetaCRTC *crtc = &manager->crtcs[i];
|
||||
|
||||
crtc->logical_monitor = NULL;
|
||||
|
||||
if (crtc->is_dirty)
|
||||
{
|
||||
crtc->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
|
||||
/* Disable outputs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *output = &manager->outputs[i];
|
||||
|
||||
if (output->is_dirty)
|
||||
{
|
||||
output->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
output->crtc = NULL;
|
||||
output->is_primary = FALSE;
|
||||
}
|
||||
|
||||
manager->screen_width = screen_width;
|
||||
manager->screen_height = screen_height;
|
||||
|
||||
meta_monitor_manager_rebuild_derived (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass)
|
||||
{
|
||||
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
|
||||
|
||||
manager_class->read_current = meta_monitor_manager_dummy_read_current;
|
||||
manager_class->apply_configuration = meta_monitor_manager_dummy_apply_config;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_dummy_init (MetaMonitorManagerDummy *manager)
|
||||
{
|
||||
}
|
40
src/backends/meta-monitor-manager-dummy.h
Normal file
40
src/backends/meta-monitor-manager-dummy.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_MONITOR_MANAGER_DUMMY_H
|
||||
#define META_MONITOR_MANAGER_DUMMY_H
|
||||
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_DUMMY (meta_monitor_manager_dummy_get_type ())
|
||||
#define META_MONITOR_MANAGER_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummy))
|
||||
#define META_MONITOR_MANAGER_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummyClass))
|
||||
#define META_IS_MONITOR_MANAGER_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_DUMMY))
|
||||
#define META_IS_MONITOR_MANAGER_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_DUMMY))
|
||||
#define META_MONITOR_MANAGER_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_DUMMY, MetaMonitorManagerDummyClass))
|
||||
|
||||
typedef struct _MetaMonitorManagerDummyClass MetaMonitorManagerDummyClass;
|
||||
typedef struct _MetaMonitorManagerDummy MetaMonitorManagerDummy;
|
||||
|
||||
GType meta_monitor_manager_dummy_get_type (void);
|
||||
|
||||
#endif /* META_MONITOR_MANAGER_DUMMY_H */
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
@ -33,11 +35,10 @@
|
||||
#include <meta/main.h>
|
||||
#include "util-private.h"
|
||||
#include <meta/errors.h>
|
||||
#include "monitor-private.h"
|
||||
|
||||
#include "meta-dbus-xrandr.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
#include "meta-monitor-config.h"
|
||||
#include "backends/native/meta-monitor-manager-kms.h"
|
||||
#include "backends/x11/meta-monitor-manager-xrandr.h"
|
||||
#include "meta-monitor-manager-dummy.h"
|
||||
|
||||
enum {
|
||||
CONFIRM_DISPLAY_CHANGE,
|
||||
@ -54,313 +55,11 @@ static int signals[SIGNALS_LAST];
|
||||
|
||||
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init));
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init));
|
||||
|
||||
static void initialize_dbus_interface (MetaMonitorManager *manager);
|
||||
|
||||
static void
|
||||
read_current_dummy (MetaMonitorManager *manager)
|
||||
{
|
||||
/* The dummy monitor config has:
|
||||
- one enabled output, LVDS, primary, at 0x0 and 1024x768
|
||||
- one free CRTC
|
||||
- two disabled outputs
|
||||
- three modes, 1024x768, 800x600 and 640x480
|
||||
- no clones are possible (use different CRTCs)
|
||||
|
||||
Low-level IDs should be assigned sequentially, to
|
||||
mimick what XRandR and KMS do
|
||||
*/
|
||||
|
||||
manager->max_screen_width = 65535;
|
||||
manager->max_screen_height = 65535;
|
||||
manager->screen_width = 1024;
|
||||
manager->screen_height = 768;
|
||||
|
||||
manager->modes = g_new0 (MetaMonitorMode, 6);
|
||||
manager->n_modes = 6;
|
||||
|
||||
manager->modes[0].mode_id = 1;
|
||||
manager->modes[0].width = 1024;
|
||||
manager->modes[0].height = 768;
|
||||
manager->modes[0].refresh_rate = 60.0;
|
||||
|
||||
manager->modes[1].mode_id = 2;
|
||||
manager->modes[1].width = 800;
|
||||
manager->modes[1].height = 600;
|
||||
manager->modes[1].refresh_rate = 60.0;
|
||||
|
||||
manager->modes[2].mode_id = 3;
|
||||
manager->modes[2].width = 640;
|
||||
manager->modes[2].height = 480;
|
||||
manager->modes[2].refresh_rate = 60.0;
|
||||
|
||||
manager->modes[3].mode_id = 4;
|
||||
manager->modes[3].width = 1920;
|
||||
manager->modes[3].height = 1080;
|
||||
manager->modes[3].refresh_rate = 60.0;
|
||||
|
||||
manager->modes[4].mode_id = 5;
|
||||
manager->modes[4].width = 1920;
|
||||
manager->modes[4].height = 1080;
|
||||
manager->modes[4].refresh_rate = 55.0;
|
||||
|
||||
manager->modes[5].mode_id = 6;
|
||||
manager->modes[5].width = 1600;
|
||||
manager->modes[5].height = 900;
|
||||
manager->modes[5].refresh_rate = 60.0;
|
||||
|
||||
manager->crtcs = g_new0 (MetaCRTC, 3);
|
||||
manager->n_crtcs = 3;
|
||||
|
||||
manager->crtcs[0].crtc_id = 4;
|
||||
manager->crtcs[0].rect.x = 0;
|
||||
manager->crtcs[0].rect.y = 0;
|
||||
manager->crtcs[0].rect.width = manager->modes[0].width;
|
||||
manager->crtcs[0].rect.height = manager->modes[0].height;
|
||||
manager->crtcs[0].current_mode = &manager->modes[0];
|
||||
manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS;
|
||||
manager->crtcs[0].is_dirty = FALSE;
|
||||
manager->crtcs[0].logical_monitor = NULL;
|
||||
|
||||
manager->crtcs[1].crtc_id = 5;
|
||||
manager->crtcs[1].rect.x = 0;
|
||||
manager->crtcs[1].rect.y = 0;
|
||||
manager->crtcs[1].rect.width = 0;
|
||||
manager->crtcs[1].rect.height = 0;
|
||||
manager->crtcs[1].current_mode = NULL;
|
||||
manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS;
|
||||
manager->crtcs[1].is_dirty = FALSE;
|
||||
manager->crtcs[1].logical_monitor = NULL;
|
||||
|
||||
manager->crtcs[2].crtc_id = 5;
|
||||
manager->crtcs[2].rect.x = 0;
|
||||
manager->crtcs[2].rect.y = 0;
|
||||
manager->crtcs[2].rect.width = 0;
|
||||
manager->crtcs[2].rect.height = 0;
|
||||
manager->crtcs[2].current_mode = NULL;
|
||||
manager->crtcs[2].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
manager->crtcs[2].all_transforms = ALL_WL_TRANSFORMS;
|
||||
manager->crtcs[2].is_dirty = FALSE;
|
||||
manager->crtcs[2].logical_monitor = NULL;
|
||||
|
||||
manager->outputs = g_new0 (MetaOutput, 3);
|
||||
manager->n_outputs = 3;
|
||||
|
||||
manager->outputs[0].crtc = NULL;
|
||||
manager->outputs[0].output_id = 6;
|
||||
manager->outputs[0].name = g_strdup ("HDMI");
|
||||
manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
|
||||
manager->outputs[0].product = g_strdup ("unknown");
|
||||
manager->outputs[0].serial = g_strdup ("0xC0F01A");
|
||||
manager->outputs[0].width_mm = 510;
|
||||
manager->outputs[0].height_mm = 287;
|
||||
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
manager->outputs[0].preferred_mode = &manager->modes[3];
|
||||
manager->outputs[0].n_modes = 5;
|
||||
manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 5);
|
||||
manager->outputs[0].modes[0] = &manager->modes[0];
|
||||
manager->outputs[0].modes[1] = &manager->modes[1];
|
||||
manager->outputs[0].modes[2] = &manager->modes[2];
|
||||
manager->outputs[0].modes[3] = &manager->modes[3];
|
||||
manager->outputs[0].modes[4] = &manager->modes[4];
|
||||
manager->outputs[0].n_possible_crtcs = 3;
|
||||
manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 3);
|
||||
manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0];
|
||||
manager->outputs[0].possible_crtcs[1] = &manager->crtcs[1];
|
||||
manager->outputs[0].possible_crtcs[2] = &manager->crtcs[2];
|
||||
manager->outputs[0].n_possible_clones = 0;
|
||||
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0);
|
||||
manager->outputs[0].backlight = -1;
|
||||
manager->outputs[0].backlight_min = 0;
|
||||
manager->outputs[0].backlight_max = 0;
|
||||
|
||||
manager->outputs[1].crtc = &manager->crtcs[0];
|
||||
manager->outputs[1].output_id = 7;
|
||||
manager->outputs[1].name = g_strdup ("LVDS");
|
||||
manager->outputs[1].vendor = g_strdup ("MetaProducts Inc.");
|
||||
manager->outputs[1].product = g_strdup ("unknown");
|
||||
manager->outputs[1].serial = g_strdup ("0xC0FFEE");
|
||||
manager->outputs[1].width_mm = 222;
|
||||
manager->outputs[1].height_mm = 125;
|
||||
manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
manager->outputs[1].preferred_mode = &manager->modes[5];
|
||||
manager->outputs[1].n_modes = 4;
|
||||
manager->outputs[1].modes = g_new0 (MetaMonitorMode *, 4);
|
||||
manager->outputs[1].modes[0] = &manager->modes[0];
|
||||
manager->outputs[1].modes[1] = &manager->modes[1];
|
||||
manager->outputs[1].modes[2] = &manager->modes[2];
|
||||
manager->outputs[1].modes[3] = &manager->modes[5];
|
||||
manager->outputs[1].n_possible_crtcs = 3;
|
||||
manager->outputs[1].possible_crtcs = g_new0 (MetaCRTC *, 3);
|
||||
manager->outputs[1].possible_crtcs[0] = &manager->crtcs[0];
|
||||
manager->outputs[1].possible_crtcs[1] = &manager->crtcs[1];
|
||||
manager->outputs[1].possible_crtcs[2] = &manager->crtcs[2];
|
||||
manager->outputs[1].n_possible_clones = 0;
|
||||
manager->outputs[1].possible_clones = g_new0 (MetaOutput *, 0);
|
||||
manager->outputs[1].backlight = -1;
|
||||
manager->outputs[1].backlight_min = 0;
|
||||
manager->outputs[1].backlight_max = 0;
|
||||
|
||||
manager->outputs[2].crtc = NULL;
|
||||
manager->outputs[2].output_id = 8;
|
||||
manager->outputs[2].name = g_strdup ("VGA");
|
||||
manager->outputs[2].vendor = g_strdup ("MetaProducts Inc.");
|
||||
manager->outputs[2].product = g_strdup ("unknown");
|
||||
manager->outputs[2].serial = g_strdup ("0xC4FE");
|
||||
manager->outputs[2].width_mm = 309;
|
||||
manager->outputs[2].height_mm = 174;
|
||||
manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
manager->outputs[2].preferred_mode = &manager->modes[0];
|
||||
manager->outputs[2].n_modes = 3;
|
||||
manager->outputs[2].modes = g_new0 (MetaMonitorMode *, 3);
|
||||
manager->outputs[2].modes[0] = &manager->modes[0];
|
||||
manager->outputs[2].modes[1] = &manager->modes[1];
|
||||
manager->outputs[2].modes[2] = &manager->modes[2];
|
||||
manager->outputs[2].n_possible_crtcs = 3;
|
||||
manager->outputs[2].possible_crtcs = g_new0 (MetaCRTC *, 3);
|
||||
manager->outputs[2].possible_crtcs[0] = &manager->crtcs[0];
|
||||
manager->outputs[2].possible_crtcs[1] = &manager->crtcs[1];
|
||||
manager->outputs[2].possible_crtcs[2] = &manager->crtcs[2];
|
||||
manager->outputs[2].n_possible_clones = 0;
|
||||
manager->outputs[2].possible_clones = g_new0 (MetaOutput *, 0);
|
||||
manager->outputs[2].backlight = -1;
|
||||
manager->outputs[2].backlight_min = 0;
|
||||
manager->outputs[2].backlight_max = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_config_dummy (MetaMonitorManager *manager,
|
||||
MetaCRTCInfo **crtcs,
|
||||
unsigned int n_crtcs,
|
||||
MetaOutputInfo **outputs,
|
||||
unsigned int n_outputs)
|
||||
{
|
||||
unsigned i;
|
||||
int screen_width = 0, screen_height = 0;
|
||||
|
||||
for (i = 0; i < n_crtcs; i++)
|
||||
{
|
||||
MetaCRTCInfo *crtc_info = crtcs[i];
|
||||
MetaCRTC *crtc = crtc_info->crtc;
|
||||
crtc->is_dirty = TRUE;
|
||||
|
||||
if (crtc_info->mode == NULL)
|
||||
{
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaMonitorMode *mode;
|
||||
MetaOutput *output;
|
||||
int i, n_outputs;
|
||||
int width, height;
|
||||
|
||||
mode = crtc_info->mode;
|
||||
|
||||
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
||||
{
|
||||
width = mode->height;
|
||||
height = mode->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = mode->width;
|
||||
height = mode->height;
|
||||
}
|
||||
|
||||
crtc->rect.x = crtc_info->x;
|
||||
crtc->rect.y = crtc_info->y;
|
||||
crtc->rect.width = width;
|
||||
crtc->rect.height = height;
|
||||
crtc->current_mode = mode;
|
||||
crtc->transform = crtc_info->transform;
|
||||
|
||||
screen_width = MAX (screen_width, crtc_info->x + width);
|
||||
screen_height = MAX (screen_height, crtc_info->y + height);
|
||||
|
||||
n_outputs = crtc_info->outputs->len;
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
output = ((MetaOutput**)crtc_info->outputs->pdata)[i];
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutputInfo *output_info = outputs[i];
|
||||
MetaOutput *output = output_info->output;
|
||||
|
||||
output->is_primary = output_info->is_primary;
|
||||
output->is_presentation = output_info->is_presentation;
|
||||
}
|
||||
|
||||
/* Disable CRTCs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_crtcs; i++)
|
||||
{
|
||||
MetaCRTC *crtc = &manager->crtcs[i];
|
||||
|
||||
crtc->logical_monitor = NULL;
|
||||
|
||||
if (crtc->is_dirty)
|
||||
{
|
||||
crtc->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
|
||||
/* Disable outputs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *output = &manager->outputs[i];
|
||||
|
||||
if (output->is_dirty)
|
||||
{
|
||||
output->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
output->crtc = NULL;
|
||||
output->is_primary = FALSE;
|
||||
}
|
||||
|
||||
manager->screen_width = screen_width;
|
||||
manager->screen_height = screen_height;
|
||||
|
||||
meta_monitor_manager_rebuild_derived (manager);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_edid_dummy (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_edid_file_dummy (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_init (MetaMonitorManager *manager)
|
||||
{
|
||||
@ -469,6 +168,40 @@ 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)
|
||||
{
|
||||
@ -478,7 +211,7 @@ meta_monitor_manager_new (void)
|
||||
env = g_getenv ("META_DEBUG_MULTIMONITOR");
|
||||
|
||||
if (env == NULL)
|
||||
type = META_TYPE_MONITOR_MANAGER_XRANDR;
|
||||
type = get_default_backend ();
|
||||
else if (strcmp (env, "xrandr") == 0)
|
||||
type = META_TYPE_MONITOR_MANAGER_XRANDR;
|
||||
else
|
||||
@ -513,17 +246,18 @@ meta_monitor_manager_constructed (GObject *object)
|
||||
MetaOutput *old_outputs;
|
||||
MetaCRTC *old_crtcs;
|
||||
MetaMonitorMode *old_modes;
|
||||
int n_old_outputs;
|
||||
unsigned int n_old_outputs, n_old_modes;
|
||||
|
||||
old_outputs = manager->outputs;
|
||||
n_old_outputs = manager->n_outputs;
|
||||
old_modes = manager->modes;
|
||||
n_old_modes = manager->n_modes;
|
||||
old_crtcs = manager->crtcs;
|
||||
|
||||
read_current_config (manager);
|
||||
|
||||
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
||||
g_free (old_modes);
|
||||
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
|
||||
g_free (old_crtcs);
|
||||
}
|
||||
|
||||
@ -565,19 +299,39 @@ meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
||||
g_free (old_outputs[i].modes);
|
||||
g_free (old_outputs[i].possible_crtcs);
|
||||
g_free (old_outputs[i].possible_clones);
|
||||
|
||||
if (old_outputs[i].driver_notify)
|
||||
old_outputs[i].driver_notify (&old_outputs[i]);
|
||||
}
|
||||
|
||||
g_free (old_outputs);
|
||||
}
|
||||
|
||||
void
|
||||
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
|
||||
int n_old_modes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_old_modes; i++)
|
||||
{
|
||||
g_free (old_modes[i].name);
|
||||
|
||||
if (old_modes[i].driver_notify)
|
||||
old_modes[i].driver_notify (&old_modes[i]);
|
||||
}
|
||||
|
||||
g_free (old_modes);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_finalize (GObject *object)
|
||||
{
|
||||
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
|
||||
|
||||
meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
|
||||
meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes);
|
||||
g_free (manager->monitor_infos);
|
||||
g_free (manager->modes);
|
||||
g_free (manager->crtcs);
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
|
||||
@ -635,6 +389,20 @@ meta_monitor_manager_get_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
meta_monitor_manager_real_read_edid (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
meta_monitor_manager_real_get_edid_file (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
|
||||
{
|
||||
@ -646,10 +414,8 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
|
||||
object_class->dispose = meta_monitor_manager_dispose;
|
||||
object_class->finalize = meta_monitor_manager_finalize;
|
||||
|
||||
klass->read_current = read_current_dummy;
|
||||
klass->apply_configuration = apply_config_dummy;
|
||||
klass->get_edid_file = get_edid_file_dummy;
|
||||
klass->read_edid = read_edid_dummy;
|
||||
klass->get_edid_file = meta_monitor_manager_real_get_edid_file;
|
||||
klass->read_edid = meta_monitor_manager_real_read_edid;
|
||||
|
||||
signals[CONFIRM_DISPLAY_CHANGE] =
|
||||
g_signal_new ("confirm-display-change",
|
||||
@ -1453,12 +1219,21 @@ meta_monitor_manager_get_resources (MetaMonitorManager *manager,
|
||||
MetaOutput **outputs,
|
||||
unsigned int *n_outputs)
|
||||
{
|
||||
*modes = manager->modes;
|
||||
*n_modes = manager->n_modes;
|
||||
*crtcs = manager->crtcs;
|
||||
*n_crtcs = manager->n_crtcs;
|
||||
*outputs = manager->outputs;
|
||||
*n_outputs = manager->n_outputs;
|
||||
if (modes)
|
||||
{
|
||||
*modes = manager->modes;
|
||||
*n_modes = manager->n_modes;
|
||||
}
|
||||
if (crtcs)
|
||||
{
|
||||
*crtcs = manager->crtcs;
|
||||
*n_crtcs = manager->n_crtcs;
|
||||
}
|
||||
if (outputs)
|
||||
{
|
||||
*outputs = manager->outputs;
|
||||
*n_outputs = manager->n_outputs;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
@ -42,31 +42,16 @@
|
||||
#include <meta/screen.h>
|
||||
#include "stack-tracker.h"
|
||||
#include "ui.h"
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include <wayland-server.h>
|
||||
#endif
|
||||
#include "meta-xrandr-shared.h"
|
||||
|
||||
#include "meta-dbus-xrandr.h"
|
||||
#include "meta-display-config-shared.h"
|
||||
#include "meta-dbus-display-config.h"
|
||||
|
||||
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
|
||||
typedef struct _MetaMonitorManager MetaMonitorManager;
|
||||
typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass;
|
||||
typedef struct _MetaMonitorConfig MetaMonitorConfig;
|
||||
|
||||
#ifndef HAVE_WAYLAND
|
||||
enum wl_output_transform {
|
||||
WL_OUTPUT_TRANSFORM_NORMAL,
|
||||
WL_OUTPUT_TRANSFORM_90,
|
||||
WL_OUTPUT_TRANSFORM_180,
|
||||
WL_OUTPUT_TRANSFORM_270,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_90,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_180,
|
||||
WL_OUTPUT_TRANSFORM_FLIPPED_270
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct _MetaOutput MetaOutput;
|
||||
typedef struct _MetaCRTC MetaCRTC;
|
||||
typedef struct _MetaMonitorMode MetaMonitorMode;
|
||||
@ -115,6 +100,9 @@ struct _MetaOutput
|
||||
gboolean is_primary;
|
||||
gboolean is_presentation;
|
||||
|
||||
gpointer driver_private;
|
||||
GDestroyNotify driver_notify;
|
||||
|
||||
/* get a new preferred mode on hotplug events, to handle dynamic guest resizing */
|
||||
gboolean hotplug_mode_update;
|
||||
};
|
||||
@ -134,16 +122,23 @@ struct _MetaCRTC
|
||||
|
||||
/* Used when changing configuration */
|
||||
gboolean is_dirty;
|
||||
|
||||
/* Updated by MetaCursorTracker */
|
||||
gboolean has_hw_cursor;
|
||||
};
|
||||
|
||||
struct _MetaMonitorMode
|
||||
{
|
||||
/* The low-level ID of this mode, used to apply back configuration */
|
||||
glong mode_id;
|
||||
char *name;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
float refresh_rate;
|
||||
|
||||
gpointer driver_private;
|
||||
GDestroyNotify driver_notify;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -232,8 +227,6 @@ struct _MetaMonitorManager
|
||||
CRTCs refer to stuff that can drive outputs
|
||||
(like encoders, but less tied to the HW),
|
||||
while monitor_infos refer to logical ones.
|
||||
|
||||
See also the comment in monitor-private.h
|
||||
*/
|
||||
MetaOutput *outputs;
|
||||
unsigned int n_outputs;
|
||||
@ -340,50 +333,13 @@ void meta_monitor_manager_apply_configuration (MetaMonitorManager
|
||||
void meta_monitor_manager_confirm_configuration (MetaMonitorManager *manager,
|
||||
gboolean ok);
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ())
|
||||
#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr))
|
||||
#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
|
||||
#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR))
|
||||
#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR))
|
||||
#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
|
||||
|
||||
typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass;
|
||||
typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
|
||||
|
||||
GType meta_monitor_manager_xrandr_get_type (void);
|
||||
|
||||
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
|
||||
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
|
||||
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||
#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
|
||||
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG))
|
||||
#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
|
||||
|
||||
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MetaMonitorConfig *meta_monitor_config_new (void);
|
||||
|
||||
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_monitor_config_make_default (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_monitor_config_update_current (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
|
||||
|
||||
void meta_monitor_config_restore_previous (MetaMonitorConfig *config,
|
||||
MetaMonitorManager *manager);
|
||||
|
||||
void meta_crtc_info_free (MetaCRTCInfo *info);
|
||||
void meta_output_info_free (MetaOutputInfo *info);
|
||||
|
||||
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
|
||||
int n_old_outputs);
|
||||
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
|
||||
int n_old_modes);
|
||||
gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
|
||||
|
||||
/* Returns true if transform causes width and height to be inverted
|
219
src/backends/native/meta-idle-monitor-native.c
Normal file
219
src/backends/native/meta-idle-monitor-native.c
Normal file
@ -0,0 +1,219 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-idle-monitor-native.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
|
||||
#include <meta/util.h>
|
||||
#include "display-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct _MetaIdleMonitorNative
|
||||
{
|
||||
MetaIdleMonitor parent;
|
||||
|
||||
guint64 last_event_time;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorNativeClass
|
||||
{
|
||||
MetaIdleMonitorClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
MetaIdleMonitorWatch base;
|
||||
|
||||
GSource *timeout_source;
|
||||
} MetaIdleMonitorWatchNative;
|
||||
|
||||
G_DEFINE_TYPE (MetaIdleMonitorNative, meta_idle_monitor_native, META_TYPE_IDLE_MONITOR)
|
||||
|
||||
static gint64
|
||||
meta_idle_monitor_native_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
|
||||
|
||||
return (g_get_monotonic_time () - monitor_native->last_event_time) / 1000;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
static guint32 serial = 0;
|
||||
g_atomic_int_inc (&serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
native_dispatch_timeout (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native = user_data;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
g_source_set_ready_time (watch_native->timeout_source, -1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs native_source_funcs = {
|
||||
NULL, /* prepare */
|
||||
NULL, /* check */
|
||||
native_dispatch_timeout,
|
||||
NULL, /* finalize */
|
||||
};
|
||||
|
||||
static void
|
||||
free_watch (gpointer data)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native = data;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
MetaIdleMonitor *monitor = watch->monitor;
|
||||
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
if (watch->notify != NULL)
|
||||
watch->notify (watch->user_data);
|
||||
|
||||
if (watch_native->timeout_source != NULL)
|
||||
g_source_destroy (watch_native->timeout_source);
|
||||
|
||||
g_object_unref (monitor);
|
||||
g_slice_free (MetaIdleMonitorWatchNative, watch_native);
|
||||
}
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
meta_idle_monitor_native_make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native;
|
||||
MetaIdleMonitorWatch *watch;
|
||||
MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
|
||||
|
||||
watch_native = g_slice_new0 (MetaIdleMonitorWatchNative);
|
||||
watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
|
||||
watch->monitor = monitor;
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
watch->timeout_msec = timeout_msec;
|
||||
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
GSource *source = g_source_new (&native_source_funcs, sizeof (GSource));
|
||||
|
||||
g_source_set_callback (source, NULL, watch, NULL);
|
||||
g_source_set_ready_time (source, monitor_native->last_event_time + timeout_msec * 1000);
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
|
||||
watch_native->timeout_source = source;
|
||||
}
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_native_class_init (MetaIdleMonitorNativeClass *klass)
|
||||
{
|
||||
MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass);
|
||||
|
||||
idle_monitor_class->get_idletime = meta_idle_monitor_native_get_idletime;
|
||||
idle_monitor_class->make_watch = meta_idle_monitor_native_make_watch;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor_native)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_native);
|
||||
|
||||
monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaIdleMonitorNative *monitor_native;
|
||||
GList *fired_watches;
|
||||
} CheckNativeClosure;
|
||||
|
||||
static gboolean
|
||||
check_native_watch (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native = value;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
CheckNativeClosure *closure = user_data;
|
||||
gboolean steal;
|
||||
|
||||
if (watch->timeout_msec == 0)
|
||||
{
|
||||
closure->fired_watches = g_list_prepend (closure->fired_watches, watch);
|
||||
steal = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch_native->timeout_source,
|
||||
closure->monitor_native->last_event_time +
|
||||
watch->timeout_msec * 1000);
|
||||
steal = FALSE;
|
||||
}
|
||||
|
||||
return steal;
|
||||
}
|
||||
|
||||
static void
|
||||
fire_native_watch (gpointer watch,
|
||||
gpointer data)
|
||||
{
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
|
||||
CheckNativeClosure closure;
|
||||
|
||||
monitor_native->last_event_time = g_get_monotonic_time ();
|
||||
|
||||
closure.monitor_native = monitor_native;
|
||||
closure.fired_watches = NULL;
|
||||
g_hash_table_foreach_steal (monitor->watches, check_native_watch, &closure);
|
||||
|
||||
g_list_foreach (closure.fired_watches, fire_native_watch, NULL);
|
||||
g_list_free (closure.fired_watches);
|
||||
}
|
43
src/backends/native/meta-idle-monitor-native.h
Normal file
43
src/backends/native/meta-idle-monitor-native.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#ifndef META_IDLE_MONITOR_NATIVE_H
|
||||
#define META_IDLE_MONITOR_NATIVE_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
|
||||
#define META_TYPE_IDLE_MONITOR_NATIVE (meta_idle_monitor_native_get_type ())
|
||||
#define META_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNative))
|
||||
#define META_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass))
|
||||
#define META_IS_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_NATIVE))
|
||||
#define META_IS_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_NATIVE))
|
||||
#define META_IDLE_MONITOR_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass))
|
||||
|
||||
typedef struct _MetaIdleMonitorNative MetaIdleMonitorNative;
|
||||
typedef struct _MetaIdleMonitorNativeClass MetaIdleMonitorNativeClass;
|
||||
|
||||
GType meta_idle_monitor_native_get_type (void);
|
||||
|
||||
void meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor);
|
||||
|
||||
#endif /* META_IDLE_MONITOR_NATIVE_H */
|
939
src/backends/native/meta-monitor-manager-kms.c
Normal file
939
src/backends/native/meta-monitor-manager-kms.c
Normal file
@ -0,0 +1,939 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-monitor-manager-kms.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include <meta/main.h>
|
||||
#include <meta/errors.h>
|
||||
#include "edid.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
typedef struct {
|
||||
drmModeConnector *connector;
|
||||
|
||||
unsigned n_encoders;
|
||||
drmModeEncoderPtr *encoders;
|
||||
drmModeEncoderPtr current_encoder;
|
||||
|
||||
/* bitmasks of encoder position in the resources array */
|
||||
uint32_t encoder_mask;
|
||||
uint32_t enc_clone_mask;
|
||||
|
||||
uint32_t dpms_prop_id;
|
||||
uint32_t edid_blob_id;
|
||||
} MetaOutputKms;
|
||||
|
||||
struct _MetaMonitorManagerKms
|
||||
{
|
||||
MetaMonitorManager parent_instance;
|
||||
|
||||
int fd;
|
||||
|
||||
drmModeConnector **connectors;
|
||||
unsigned int n_connectors;
|
||||
|
||||
drmModeEncoder **encoders;
|
||||
unsigned int n_encoders;
|
||||
|
||||
drmModeEncoder *current_encoder;
|
||||
};
|
||||
|
||||
struct _MetaMonitorManagerKmsClass
|
||||
{
|
||||
MetaMonitorManagerClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
|
||||
|
||||
static void
|
||||
free_resources (MetaMonitorManagerKms *manager_kms)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < manager_kms->n_encoders; i++)
|
||||
drmModeFreeEncoder (manager_kms->encoders[i]);
|
||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||
drmModeFreeConnector (manager_kms->connectors[i]);
|
||||
|
||||
g_free (manager_kms->encoders);
|
||||
g_free (manager_kms->connectors);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_outputs (const void *one,
|
||||
const void *two)
|
||||
{
|
||||
const MetaOutput *o_one = one, *o_two = two;
|
||||
|
||||
return strcmp (o_one->name, o_two->name);
|
||||
}
|
||||
|
||||
static char *
|
||||
make_output_name (drmModeConnector *connector)
|
||||
{
|
||||
static const char * const connector_type_names[] = {
|
||||
"unknown", "VGA", "DVII", "DVID", "DVID", "Composite",
|
||||
"SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort",
|
||||
"HDMIA", "HDMIB", "TV", "eDP"
|
||||
};
|
||||
const char *connector_type_name;
|
||||
|
||||
if (connector->connector_type < G_N_ELEMENTS (connector_type_names))
|
||||
connector_type_name = connector_type_names[connector->connector_type];
|
||||
else
|
||||
connector_type_name = "unknown";
|
||||
|
||||
return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_output_destroy_notify (MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms;
|
||||
unsigned i;
|
||||
|
||||
output_kms = output->driver_private;
|
||||
|
||||
for (i = 0; i < output_kms->n_encoders; i++)
|
||||
drmModeFreeEncoder (output_kms->encoders[i]);
|
||||
g_free (output_kms->encoders);
|
||||
|
||||
g_slice_free (MetaOutputKms, output_kms);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_mode_destroy_notify (MetaMonitorMode *output)
|
||||
{
|
||||
g_slice_free (drmModeModeInfo, output->driver_private);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drm_mode_equal (gconstpointer one,
|
||||
gconstpointer two)
|
||||
{
|
||||
const drmModeModeInfo *m_one = one;
|
||||
const drmModeModeInfo *m_two = two;
|
||||
|
||||
return m_one->clock == m_two->clock &&
|
||||
m_one->hdisplay == m_two->hdisplay &&
|
||||
m_one->hsync_start == m_two->hsync_start &&
|
||||
m_one->hsync_end == m_two->hsync_end &&
|
||||
m_one->htotal == m_two->htotal &&
|
||||
m_one->hskew == m_two->hskew &&
|
||||
m_one->vdisplay == m_two->vdisplay &&
|
||||
m_one->vsync_start == m_two->vsync_start &&
|
||||
m_one->vsync_end == m_two->vsync_end &&
|
||||
m_one->vtotal == m_two->vtotal &&
|
||||
m_one->vscan == m_two->vscan &&
|
||||
m_one->vrefresh == m_two->vrefresh &&
|
||||
m_one->flags == m_two->flags &&
|
||||
m_one->type == m_two->type &&
|
||||
strncmp (m_one->name, m_two->name, DRM_DISPLAY_MODE_LEN) == 0;
|
||||
}
|
||||
|
||||
static guint
|
||||
drm_mode_hash (gconstpointer ptr)
|
||||
{
|
||||
const drmModeModeInfo *mode = ptr;
|
||||
guint hash = 0;
|
||||
|
||||
/* We don't include the name in the hash because it's generally
|
||||
derived from the other fields (hdisplay, vdisplay and flags)
|
||||
*/
|
||||
|
||||
hash ^= mode->clock;
|
||||
hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end;
|
||||
hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end;
|
||||
hash ^= mode->vrefresh;
|
||||
hash ^= mode->flags ^ mode->type;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
find_properties (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutputKms *output_kms)
|
||||
{
|
||||
drmModePropertyPtr prop;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < output_kms->connector->count_props; i++)
|
||||
{
|
||||
prop = drmModeGetProperty (manager_kms->fd, output_kms->connector->props[i]);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
|
||||
strcmp(prop->name, "DPMS") == 0)
|
||||
output_kms->dpms_prop_id = prop->prop_id;
|
||||
else if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
||||
strcmp (prop->name, "EDID") == 0)
|
||||
output_kms->edid_blob_id = output_kms->connector->prop_values[i];
|
||||
|
||||
drmModeFreeProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
read_output_edid (MetaMonitorManagerKms *manager_kms,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
drmModePropertyBlobPtr edid_blob = NULL;
|
||||
|
||||
if (output_kms->edid_blob_id == 0)
|
||||
return NULL;
|
||||
|
||||
edid_blob = drmModeGetPropertyBlob (manager_kms->fd, output_kms->edid_blob_id);
|
||||
if (!edid_blob)
|
||||
{
|
||||
meta_warning ("Failed to read EDID of output %s: %s\n", output->name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (edid_blob->length > 0)
|
||||
return g_bytes_new_with_free_func (edid_blob->data, edid_blob->length,
|
||||
(GDestroyNotify)drmModeFreePropertyBlob, edid_blob);
|
||||
else
|
||||
{
|
||||
drmModeFreePropertyBlob (edid_blob);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static MetaMonitorMode *
|
||||
find_meta_mode (MetaMonitorManager *manager,
|
||||
const drmModeModeInfo *drm_mode)
|
||||
{
|
||||
unsigned k;
|
||||
|
||||
for (k = 0; k < manager->n_modes; k++)
|
||||
{
|
||||
if (drm_mode_equal (drm_mode, manager->modes[k].driver_private))
|
||||
return &manager->modes[k];
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MetaOutput *
|
||||
find_output_by_id (MetaOutput *outputs,
|
||||
unsigned n_outputs,
|
||||
glong id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
if (outputs[i].output_id == id)
|
||||
return &outputs[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
drmModeRes *resources;
|
||||
GHashTable *modes;
|
||||
GHashTableIter iter;
|
||||
drmModeModeInfo *mode;
|
||||
unsigned int i, j, k;
|
||||
unsigned int n_actual_outputs;
|
||||
int width, height;
|
||||
MetaOutput *old_outputs;
|
||||
unsigned int n_old_outputs;
|
||||
|
||||
resources = drmModeGetResources(manager_kms->fd);
|
||||
modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
|
||||
|
||||
manager->max_screen_width = resources->max_width;
|
||||
manager->max_screen_height = resources->max_height;
|
||||
|
||||
manager->power_save_mode = META_POWER_SAVE_ON;
|
||||
|
||||
old_outputs = manager->outputs;
|
||||
n_old_outputs = manager->n_outputs;
|
||||
|
||||
/* Note: we must not free the public structures (output, crtc, monitor
|
||||
mode and monitor info) here, they must be kept alive until the API
|
||||
users are done with them after we emit monitors-changed, and thus
|
||||
are freed by the platform-independent layer. */
|
||||
free_resources (manager_kms);
|
||||
|
||||
manager_kms->n_connectors = resources->count_connectors;
|
||||
manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
|
||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||
{
|
||||
drmModeConnector *connector;
|
||||
|
||||
connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]);
|
||||
manager_kms->connectors[i] = connector;
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED)
|
||||
{
|
||||
/* Collect all modes for this connector */
|
||||
for (j = 0; j < (unsigned)connector->count_modes; j++)
|
||||
g_hash_table_add (modes, &connector->modes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
manager_kms->n_encoders = resources->count_encoders;
|
||||
manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders);
|
||||
for (i = 0; i < manager_kms->n_encoders; i++)
|
||||
{
|
||||
manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd,
|
||||
resources->encoders[i]);
|
||||
}
|
||||
|
||||
manager->n_modes = g_hash_table_size (modes);
|
||||
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
|
||||
g_hash_table_iter_init (&iter, modes);
|
||||
i = 0;
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode))
|
||||
{
|
||||
MetaMonitorMode *meta_mode;
|
||||
|
||||
meta_mode = &manager->modes[i];
|
||||
|
||||
meta_mode->mode_id = i;
|
||||
meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN);
|
||||
meta_mode->width = mode->hdisplay;
|
||||
meta_mode->height = mode->vdisplay;
|
||||
meta_mode->refresh_rate = (1000 * mode->clock /
|
||||
((float)mode->htotal * mode->vtotal));
|
||||
|
||||
meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
|
||||
meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
|
||||
|
||||
i++;
|
||||
}
|
||||
g_hash_table_destroy (modes);
|
||||
|
||||
manager->n_crtcs = resources->count_crtcs;
|
||||
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
|
||||
width = 0; height = 0;
|
||||
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
|
||||
{
|
||||
drmModeCrtc *crtc;
|
||||
MetaCRTC *meta_crtc;
|
||||
|
||||
crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
|
||||
|
||||
meta_crtc = &manager->crtcs[i];
|
||||
|
||||
meta_crtc->crtc_id = crtc->crtc_id;
|
||||
meta_crtc->rect.x = crtc->x;
|
||||
meta_crtc->rect.y = crtc->y;
|
||||
meta_crtc->rect.width = crtc->width;
|
||||
meta_crtc->rect.height = crtc->height;
|
||||
meta_crtc->is_dirty = FALSE;
|
||||
meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
/* FIXME: implement! */
|
||||
meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
|
||||
if (crtc->mode_valid)
|
||||
{
|
||||
for (j = 0; j < manager->n_modes; j++)
|
||||
{
|
||||
if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private))
|
||||
{
|
||||
meta_crtc->current_mode = &manager->modes[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width);
|
||||
height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
|
||||
}
|
||||
|
||||
drmModeFreeCrtc (crtc);
|
||||
}
|
||||
|
||||
manager->screen_width = width;
|
||||
manager->screen_height = height;
|
||||
|
||||
manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
|
||||
n_actual_outputs = 0;
|
||||
|
||||
for (i = 0; i < manager_kms->n_connectors; i++)
|
||||
{
|
||||
MetaOutput *meta_output, *old_output;
|
||||
MetaOutputKms *output_kms;
|
||||
drmModeConnector *connector;
|
||||
GArray *crtcs;
|
||||
unsigned int crtc_mask;
|
||||
GBytes *edid;
|
||||
|
||||
connector = manager_kms->connectors[i];
|
||||
meta_output = &manager->outputs[n_actual_outputs];
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED)
|
||||
{
|
||||
meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms);
|
||||
meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
|
||||
|
||||
meta_output->output_id = connector->connector_id;
|
||||
meta_output->name = make_output_name (connector);
|
||||
meta_output->width_mm = connector->mmWidth;
|
||||
meta_output->height_mm = connector->mmHeight;
|
||||
|
||||
switch (connector->subpixel)
|
||||
{
|
||||
case DRM_MODE_SUBPIXEL_NONE:
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
|
||||
break;
|
||||
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
|
||||
break;
|
||||
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
|
||||
break;
|
||||
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
|
||||
break;
|
||||
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
|
||||
break;
|
||||
case DRM_MODE_SUBPIXEL_UNKNOWN:
|
||||
default:
|
||||
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
meta_output->n_modes = connector->count_modes;
|
||||
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
|
||||
for (j = 0; j < meta_output->n_modes; j++)
|
||||
meta_output->modes[j] = find_meta_mode (manager, &connector->modes[j]);
|
||||
meta_output->preferred_mode = meta_output->modes[0];
|
||||
|
||||
output_kms->connector = connector;
|
||||
output_kms->n_encoders = connector->count_encoders;
|
||||
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
||||
|
||||
crtc_mask = ~(unsigned int)0;
|
||||
for (j = 0; j < output_kms->n_encoders; j++)
|
||||
{
|
||||
output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]);
|
||||
|
||||
/* We only list CRTCs as supported if they are supported by all encoders
|
||||
for this connectors.
|
||||
|
||||
This is what xf86-video-modesetting does (see drmmode_output_init())
|
||||
*/
|
||||
crtc_mask &= output_kms->encoders[j]->possible_crtcs;
|
||||
|
||||
if (output_kms->encoders[j]->encoder_id == connector->encoder_id)
|
||||
output_kms->current_encoder = output_kms->encoders[j];
|
||||
}
|
||||
|
||||
crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
|
||||
|
||||
for (j = 0; j < manager->n_crtcs; j++)
|
||||
{
|
||||
if (crtc_mask & (1 << j))
|
||||
{
|
||||
MetaCRTC *crtc = &manager->crtcs[j];
|
||||
g_array_append_val (crtcs, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
meta_output->n_possible_crtcs = crtcs->len;
|
||||
meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
|
||||
|
||||
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
|
||||
{
|
||||
for (j = 0; j < manager->n_crtcs; j++)
|
||||
{
|
||||
if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id)
|
||||
{
|
||||
meta_output->crtc = &manager->crtcs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
meta_output->crtc = NULL;
|
||||
|
||||
old_output = find_output_by_id (old_outputs, n_old_outputs,
|
||||
meta_output->output_id);
|
||||
if (old_output)
|
||||
{
|
||||
meta_output->is_primary = old_output->is_primary;
|
||||
meta_output->is_presentation = old_output->is_presentation;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_output->is_primary = FALSE;
|
||||
meta_output->is_presentation = FALSE;
|
||||
}
|
||||
|
||||
find_properties (manager_kms, output_kms);
|
||||
|
||||
edid = read_output_edid (manager_kms, meta_output);
|
||||
if (edid)
|
||||
{
|
||||
MonitorInfo *parsed_edid;
|
||||
gsize len;
|
||||
|
||||
parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
|
||||
if (parsed_edid)
|
||||
{
|
||||
meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
|
||||
meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14);
|
||||
meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
|
||||
|
||||
g_free (parsed_edid);
|
||||
}
|
||||
|
||||
g_bytes_unref (edid);
|
||||
}
|
||||
if (!meta_output->vendor)
|
||||
{
|
||||
meta_output->vendor = g_strdup ("unknown");
|
||||
meta_output->product = g_strdup ("unknown");
|
||||
meta_output->serial = g_strdup ("unknown");
|
||||
}
|
||||
|
||||
/* FIXME: backlight is a very driver specific thing unfortunately,
|
||||
every DDX does its own thing, and the dumb KMS API does not include it.
|
||||
|
||||
For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
|
||||
(one for each major HW maker, and then some).
|
||||
We can't do the same because we're not root.
|
||||
It might be best to leave backlight out of the story and rely on the setuid
|
||||
helper in gnome-settings-daemon.
|
||||
*/
|
||||
meta_output->backlight_min = 0;
|
||||
meta_output->backlight_max = 0;
|
||||
meta_output->backlight = -1;
|
||||
|
||||
n_actual_outputs++;
|
||||
}
|
||||
}
|
||||
|
||||
manager->n_outputs = n_actual_outputs;
|
||||
manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
|
||||
|
||||
/* Sort the outputs for easier handling in MetaMonitorConfig */
|
||||
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
|
||||
|
||||
/* Now fix the clones.
|
||||
Code mostly inspired by xf86-video-modesetting. */
|
||||
|
||||
/* XXX: intel hardware doesn't usually have clones, but I only have laptops with
|
||||
intel cards, so this code was never tested! */
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
|
||||
meta_output = &manager->outputs[i];
|
||||
output_kms = meta_output->driver_private;
|
||||
|
||||
output_kms->enc_clone_mask = 0xff;
|
||||
output_kms->encoder_mask = 0;
|
||||
|
||||
for (j = 0; j < output_kms->n_encoders; j++)
|
||||
{
|
||||
for (k = 0; k < manager_kms->n_encoders; k++)
|
||||
{
|
||||
if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id)
|
||||
{
|
||||
output_kms->encoder_mask |= (1 << k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
|
||||
meta_output = &manager->outputs[i];
|
||||
output_kms = meta_output->driver_private;
|
||||
|
||||
if (output_kms->enc_clone_mask == 0)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < manager->n_outputs; j++)
|
||||
{
|
||||
MetaOutput *meta_clone;
|
||||
MetaOutputKms *clone_kms;
|
||||
|
||||
meta_clone = &manager->outputs[i];
|
||||
clone_kms = meta_clone->driver_private;
|
||||
|
||||
if (meta_clone == meta_output)
|
||||
continue;
|
||||
|
||||
if (clone_kms->encoder_mask == 0)
|
||||
continue;
|
||||
|
||||
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
|
||||
{
|
||||
meta_output->n_possible_clones++;
|
||||
meta_output->possible_clones = g_renew (MetaOutput *,
|
||||
meta_output->possible_clones,
|
||||
meta_output->n_possible_clones);
|
||||
meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drmModeFreeResources (resources);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager,
|
||||
MetaOutput *output)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
|
||||
return read_output_edid (manager_kms, output);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
MetaPowerSave mode)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
uint64_t state;
|
||||
unsigned i;
|
||||
|
||||
switch (mode) {
|
||||
case META_POWER_SAVE_ON:
|
||||
state = DRM_MODE_DPMS_ON;
|
||||
break;
|
||||
case META_POWER_SAVE_STANDBY:
|
||||
state = DRM_MODE_DPMS_STANDBY;
|
||||
break;
|
||||
case META_POWER_SAVE_SUSPEND:
|
||||
state = DRM_MODE_DPMS_SUSPEND;
|
||||
break;
|
||||
case META_POWER_SAVE_OFF:
|
||||
state = DRM_MODE_DPMS_OFF;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *meta_output;
|
||||
MetaOutputKms *output_kms;
|
||||
|
||||
meta_output = &manager->outputs[i];
|
||||
output_kms = meta_output->driver_private;
|
||||
|
||||
if (output_kms->dpms_prop_id != 0)
|
||||
{
|
||||
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id,
|
||||
output_kms->dpms_prop_id, state);
|
||||
|
||||
if (ok < 0)
|
||||
meta_warning ("Failed to set power save mode for output %s: %s\n",
|
||||
meta_output->name, strerror (errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
crtc_free (CoglKmsCrtc *crtc)
|
||||
{
|
||||
g_free (crtc->connectors);
|
||||
g_slice_free (CoglKmsCrtc, crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
|
||||
MetaCRTCInfo **crtcs,
|
||||
unsigned int n_crtcs,
|
||||
MetaOutputInfo **outputs,
|
||||
unsigned int n_outputs)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
unsigned i;
|
||||
GPtrArray *cogl_crtcs;
|
||||
int screen_width, screen_height;
|
||||
gboolean ok;
|
||||
GError *error;
|
||||
|
||||
cogl_crtcs = g_ptr_array_new_full (manager->n_crtcs, (GDestroyNotify)crtc_free);
|
||||
screen_width = 0; screen_height = 0;
|
||||
for (i = 0; i < n_crtcs; i++)
|
||||
{
|
||||
MetaCRTCInfo *crtc_info = crtcs[i];
|
||||
MetaCRTC *crtc = crtc_info->crtc;
|
||||
CoglKmsCrtc *cogl_crtc;
|
||||
|
||||
crtc->is_dirty = TRUE;
|
||||
|
||||
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
|
||||
g_ptr_array_add (cogl_crtcs, cogl_crtc);
|
||||
|
||||
if (crtc_info->mode == NULL)
|
||||
{
|
||||
cogl_crtc->id = crtc->crtc_id;
|
||||
cogl_crtc->x = 0;
|
||||
cogl_crtc->y = 0;
|
||||
cogl_crtc->count = 0;
|
||||
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
|
||||
cogl_crtc->connectors = NULL;
|
||||
cogl_crtc->count = 0;
|
||||
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaMonitorMode *mode;
|
||||
uint32_t *connectors;
|
||||
unsigned int j, n_connectors;
|
||||
int width, height;
|
||||
|
||||
mode = crtc_info->mode;
|
||||
|
||||
cogl_crtc->id = crtc->crtc_id;
|
||||
cogl_crtc->x = crtc_info->x;
|
||||
cogl_crtc->y = crtc_info->y;
|
||||
cogl_crtc->count = n_connectors = crtc_info->outputs->len;
|
||||
cogl_crtc->connectors = connectors = g_new (uint32_t, n_connectors);
|
||||
|
||||
for (j = 0; j < n_connectors; j++)
|
||||
{
|
||||
MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j);
|
||||
|
||||
connectors[j] = output->output_id;
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
}
|
||||
|
||||
memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private,
|
||||
sizeof (drmModeModeInfo));
|
||||
|
||||
if (meta_monitor_transform_is_rotated (crtc_info->transform))
|
||||
{
|
||||
width = mode->height;
|
||||
height = mode->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = mode->width;
|
||||
height = mode->height;
|
||||
}
|
||||
|
||||
screen_width = MAX (screen_width, crtc_info->x + width);
|
||||
screen_height = MAX (screen_height, crtc_info->y + height);
|
||||
|
||||
crtc->rect.x = crtc_info->x;
|
||||
crtc->rect.y = crtc_info->y;
|
||||
crtc->rect.width = width;
|
||||
crtc->rect.height = height;
|
||||
crtc->current_mode = mode;
|
||||
crtc->transform = crtc_info->transform;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
|
||||
because they weren't seen in the first loop) */
|
||||
for (i = 0; i < manager->n_crtcs; i++)
|
||||
{
|
||||
MetaCRTC *crtc = &manager->crtcs[i];
|
||||
CoglKmsCrtc *cogl_crtc;
|
||||
|
||||
crtc->logical_monitor = NULL;
|
||||
|
||||
if (crtc->is_dirty)
|
||||
{
|
||||
crtc->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
|
||||
g_ptr_array_add (cogl_crtcs, cogl_crtc);
|
||||
|
||||
cogl_crtc->id = crtc->crtc_id;
|
||||
cogl_crtc->x = 0;
|
||||
cogl_crtc->y = 0;
|
||||
cogl_crtc->count = 0;
|
||||
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
|
||||
cogl_crtc->connectors = NULL;
|
||||
cogl_crtc->count = 0;
|
||||
|
||||
crtc->rect.x = 0;
|
||||
crtc->rect.y = 0;
|
||||
crtc->rect.width = 0;
|
||||
crtc->rect.height = 0;
|
||||
crtc->current_mode = NULL;
|
||||
}
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
|
||||
error = NULL;
|
||||
ok = cogl_kms_display_set_layout (cogl_display, screen_width, screen_height,
|
||||
(CoglKmsCrtc**)cogl_crtcs->pdata, cogl_crtcs->len, &error);
|
||||
g_ptr_array_unref (cogl_crtcs);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
meta_warning ("Applying display configuration failed: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutputInfo *output_info = outputs[i];
|
||||
MetaOutput *output = output_info->output;
|
||||
|
||||
output->is_primary = output_info->is_primary;
|
||||
output->is_presentation = output_info->is_presentation;
|
||||
}
|
||||
|
||||
/* Disable outputs not mentioned in the list */
|
||||
for (i = 0; i < manager->n_outputs; i++)
|
||||
{
|
||||
MetaOutput *output = &manager->outputs[i];
|
||||
|
||||
if (output->is_dirty)
|
||||
{
|
||||
output->is_dirty = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
output->crtc = NULL;
|
||||
output->is_primary = FALSE;
|
||||
}
|
||||
|
||||
manager->screen_width = screen_width;
|
||||
manager->screen_height = screen_height;
|
||||
|
||||
meta_monitor_manager_rebuild_derived (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager,
|
||||
MetaCRTC *crtc,
|
||||
gsize *size,
|
||||
unsigned short **red,
|
||||
unsigned short **green,
|
||||
unsigned short **blue)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
drmModeCrtc *kms_crtc;
|
||||
|
||||
kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id);
|
||||
|
||||
*size = kms_crtc->gamma_size;
|
||||
*red = g_new (unsigned short, *size);
|
||||
*green = g_new (unsigned short, *size);
|
||||
*blue = g_new (unsigned short, *size);
|
||||
|
||||
drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue);
|
||||
|
||||
drmModeFreeCrtc (kms_crtc);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
|
||||
MetaCRTC *crtc,
|
||||
gsize size,
|
||||
unsigned short *red,
|
||||
unsigned short *green,
|
||||
unsigned short *blue)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
|
||||
|
||||
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
CoglRenderer *cogl_renderer;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_renderer = cogl_display_get_renderer (cogl_display);
|
||||
|
||||
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_finalize (GObject *object)
|
||||
{
|
||||
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
|
||||
|
||||
free_resources (manager_kms);
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
|
||||
{
|
||||
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_monitor_manager_kms_finalize;
|
||||
|
||||
manager_class->read_current = meta_monitor_manager_kms_read_current;
|
||||
manager_class->read_edid = meta_monitor_manager_kms_read_edid;
|
||||
manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration;
|
||||
manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode;
|
||||
manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma;
|
||||
manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma;
|
||||
}
|
||||
|
40
src/backends/native/meta-monitor-manager-kms.h
Normal file
40
src/backends/native/meta-monitor-manager-kms.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_MONITOR_MANAGER_KMS_H
|
||||
#define META_MONITOR_MANAGER_KMS_H
|
||||
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ())
|
||||
#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms))
|
||||
#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
|
||||
#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS))
|
||||
#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS))
|
||||
#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
|
||||
|
||||
typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass;
|
||||
typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms;
|
||||
|
||||
GType meta_monitor_manager_kms_get_type (void);
|
||||
|
||||
#endif /* META_MONITOR_MANAGER_KMS_H */
|
411
src/backends/native/meta-weston-launch.c
Normal file
411
src/backends/native/meta-weston-launch.c
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* 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-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_force_update (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);
|
||||
}
|
||||
|
34
src/backends/native/meta-weston-launch.h
Normal file
34
src/backends/native/meta-weston-launch.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_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_vt (MetaLauncher *self,
|
||||
signed char vt,
|
||||
GError **error);
|
||||
#endif
|
711
src/backends/native/weston-launch.c
Normal file
711
src/backends/native/weston-launch.c
Normal 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;
|
||||
}
|
68
src/backends/native/weston-launch.h
Normal file
68
src/backends/native/weston-launch.h
Normal 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
|
366
src/backends/x11/meta-idle-monitor-xsync.c
Normal file
366
src/backends/x11/meta-idle-monitor-xsync.c
Normal file
@ -0,0 +1,366 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-idle-monitor-xsync.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
|
||||
#include <meta/util.h>
|
||||
#include "display-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct _MetaIdleMonitorXSync
|
||||
{
|
||||
MetaIdleMonitor parent;
|
||||
|
||||
GHashTable *alarms;
|
||||
Display *display;
|
||||
XSyncCounter counter;
|
||||
XSyncAlarm user_active_alarm;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorXSyncClass
|
||||
{
|
||||
MetaIdleMonitorClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
MetaIdleMonitorWatch base;
|
||||
|
||||
XSyncAlarm xalarm;
|
||||
} MetaIdleMonitorWatchXSync;
|
||||
|
||||
G_DEFINE_TYPE (MetaIdleMonitorXSync, meta_idle_monitor_xsync, META_TYPE_IDLE_MONITOR)
|
||||
|
||||
static gint64
|
||||
_xsyncvalue_to_int64 (XSyncValue value)
|
||||
{
|
||||
return ((guint64) XSyncValueHigh32 (value)) << 32
|
||||
| (guint64) XSyncValueLow32 (value);
|
||||
}
|
||||
|
||||
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
|
||||
|
||||
static XSyncAlarm
|
||||
_xsync_alarm_set (MetaIdleMonitorXSync *monitor_xsync,
|
||||
XSyncTestType test_type,
|
||||
guint64 interval,
|
||||
gboolean want_events)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
XSyncValue delta;
|
||||
guint flags;
|
||||
|
||||
flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
|
||||
XSyncCAValue | XSyncCADelta | XSyncCAEvents;
|
||||
|
||||
XSyncIntToValue (&delta, 0);
|
||||
attr.trigger.counter = monitor_xsync->counter;
|
||||
attr.trigger.value_type = XSyncAbsolute;
|
||||
attr.delta = delta;
|
||||
attr.events = want_events;
|
||||
|
||||
GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
|
||||
attr.trigger.test_type = test_type;
|
||||
return XSyncCreateAlarm (monitor_xsync->display, flags, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_alarm_rescheduled (Display *dpy,
|
||||
XSyncAlarm alarm)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
|
||||
/* Some versions of Xorg have an issue where alarms aren't
|
||||
* always rescheduled. Calling XSyncChangeAlarm, even
|
||||
* without any attributes, will reschedule the alarm. */
|
||||
XSyncChangeAlarm (dpy, alarm, 0, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
set_alarm_enabled (Display *dpy,
|
||||
XSyncAlarm alarm,
|
||||
gboolean enabled)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
attr.events = enabled;
|
||||
XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
check_x11_watch (gpointer data,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatchXSync *watch_xsync = data;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync;
|
||||
XSyncAlarm alarm = (XSyncAlarm) user_data;
|
||||
|
||||
if (watch_xsync->xalarm != alarm)
|
||||
return;
|
||||
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
}
|
||||
|
||||
static char *
|
||||
counter_name_for_device (int device_id)
|
||||
{
|
||||
if (device_id > 0)
|
||||
return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
|
||||
|
||||
return g_strdup ("IDLETIME");
|
||||
}
|
||||
|
||||
static XSyncCounter
|
||||
find_idletime_counter (MetaIdleMonitorXSync *monitor_xsync)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync);
|
||||
int i;
|
||||
int ncounters;
|
||||
XSyncSystemCounter *counters;
|
||||
XSyncCounter counter = None;
|
||||
char *counter_name;
|
||||
|
||||
counter_name = counter_name_for_device (monitor->device_id);
|
||||
counters = XSyncListSystemCounters (monitor_xsync->display, &ncounters);
|
||||
for (i = 0; i < ncounters; i++)
|
||||
{
|
||||
if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0)
|
||||
{
|
||||
counter = counters[i].counter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XSyncFreeSystemCounterList (counters);
|
||||
g_free (counter_name);
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void
|
||||
init_xsync (MetaIdleMonitorXSync *monitor_xsync)
|
||||
{
|
||||
monitor_xsync->counter = find_idletime_counter (monitor_xsync);
|
||||
/* IDLETIME counter not found? */
|
||||
if (monitor_xsync->counter == None)
|
||||
{
|
||||
g_warning ("IDLETIME counter not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_xsync->user_active_alarm = _xsync_alarm_set (monitor_xsync, XSyncNegativeTransition, 1, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_xsync_dispose (GObject *object)
|
||||
{
|
||||
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
|
||||
|
||||
if (monitor_xsync->user_active_alarm != None)
|
||||
{
|
||||
XSyncDestroyAlarm (monitor_xsync->display, monitor_xsync->user_active_alarm);
|
||||
monitor_xsync->user_active_alarm = None;
|
||||
}
|
||||
|
||||
g_clear_pointer (&monitor_xsync->alarms, g_hash_table_destroy);
|
||||
|
||||
G_OBJECT_CLASS (meta_idle_monitor_xsync_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_xsync_constructed (GObject *object)
|
||||
{
|
||||
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (object);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static gint64
|
||||
meta_idle_monitor_xsync_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
|
||||
XSyncValue value;
|
||||
|
||||
if (!XSyncQueryCounter (monitor_xsync->display, monitor_xsync->counter, &value))
|
||||
return -1;
|
||||
|
||||
return _xsyncvalue_to_int64 (value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fire_watch_idle (gpointer data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = data;
|
||||
|
||||
watch->idle_source_id = 0;
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
static guint32 serial = 0;
|
||||
g_atomic_int_inc (&serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static void
|
||||
free_watch (gpointer data)
|
||||
{
|
||||
MetaIdleMonitorWatchXSync *watch_xsync = data;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_xsync;
|
||||
MetaIdleMonitor *monitor = watch->monitor;
|
||||
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
|
||||
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
if (watch->notify != NULL)
|
||||
watch->notify (watch->user_data);
|
||||
|
||||
if (watch_xsync->xalarm != monitor_xsync->user_active_alarm &&
|
||||
watch_xsync->xalarm != None)
|
||||
{
|
||||
XSyncDestroyAlarm (monitor_xsync->display, watch_xsync->xalarm);
|
||||
g_hash_table_remove (monitor_xsync->alarms, (gpointer) watch_xsync->xalarm);
|
||||
}
|
||||
|
||||
g_object_unref (monitor);
|
||||
g_slice_free (MetaIdleMonitorWatchXSync, watch_xsync);
|
||||
}
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
meta_idle_monitor_xsync_make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
|
||||
MetaIdleMonitorWatchXSync *watch_xsync;
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
watch_xsync = g_slice_new0 (MetaIdleMonitorWatchXSync);
|
||||
watch = (MetaIdleMonitorWatch *) watch_xsync;
|
||||
|
||||
watch->monitor = monitor;
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
watch->timeout_msec = timeout_msec;
|
||||
|
||||
if (monitor_xsync->user_active_alarm != None)
|
||||
{
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
watch_xsync->xalarm = _xsync_alarm_set (monitor_xsync, XSyncPositiveTransition, timeout_msec, TRUE);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_xsync->xalarm = monitor_xsync->user_active_alarm;
|
||||
|
||||
set_alarm_enabled (monitor_xsync->display, monitor_xsync->user_active_alarm, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_xsync_class_init (MetaIdleMonitorXSyncClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_idle_monitor_xsync_dispose;
|
||||
object_class->constructed = meta_idle_monitor_xsync_constructed;
|
||||
|
||||
idle_monitor_class->get_idletime = meta_idle_monitor_xsync_get_idletime;
|
||||
idle_monitor_class->make_watch = meta_idle_monitor_xsync_make_watch;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_xsync_init (MetaIdleMonitorXSync *monitor_xsync)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_xsync);
|
||||
|
||||
monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
|
||||
monitor_xsync->alarms = g_hash_table_new (NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_xsync_handle_xevent (MetaIdleMonitor *monitor,
|
||||
XSyncAlarmNotifyEvent *alarm_event)
|
||||
{
|
||||
MetaIdleMonitorXSync *monitor_xsync = META_IDLE_MONITOR_XSYNC (monitor);
|
||||
XSyncAlarm alarm;
|
||||
GList *watches;
|
||||
gboolean has_alarm;
|
||||
|
||||
if (alarm_event->state != XSyncAlarmActive)
|
||||
return;
|
||||
|
||||
alarm = alarm_event->alarm;
|
||||
|
||||
has_alarm = FALSE;
|
||||
|
||||
if (alarm == monitor_xsync->user_active_alarm)
|
||||
{
|
||||
set_alarm_enabled (monitor_xsync->display,
|
||||
alarm,
|
||||
FALSE);
|
||||
has_alarm = TRUE;
|
||||
}
|
||||
else if (g_hash_table_contains (monitor_xsync->alarms, (gpointer) alarm))
|
||||
{
|
||||
ensure_alarm_rescheduled (monitor_xsync->display,
|
||||
alarm);
|
||||
has_alarm = TRUE;
|
||||
}
|
||||
|
||||
if (has_alarm)
|
||||
{
|
||||
watches = g_hash_table_get_values (monitor->watches);
|
||||
|
||||
g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
|
||||
g_list_free (watches);
|
||||
}
|
||||
}
|
49
src/backends/x11/meta-idle-monitor-xsync.h
Normal file
49
src/backends/x11/meta-idle-monitor-xsync.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#ifndef META_IDLE_MONITOR_XSYNC_H
|
||||
#define META_IDLE_MONITOR_XSYNC_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
#define META_TYPE_IDLE_MONITOR_XSYNC (meta_idle_monitor_xsync_get_type ())
|
||||
#define META_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSync))
|
||||
#define META_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass))
|
||||
#define META_IS_IDLE_MONITOR_XSYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_XSYNC))
|
||||
#define META_IS_IDLE_MONITOR_XSYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_XSYNC))
|
||||
#define META_IDLE_MONITOR_XSYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_XSYNC, MetaIdleMonitorXSyncClass))
|
||||
|
||||
typedef struct _MetaIdleMonitorXSync MetaIdleMonitorXSync;
|
||||
typedef struct _MetaIdleMonitorXSyncClass MetaIdleMonitorXSyncClass;
|
||||
|
||||
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 */
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-monitor-manager-xrandr.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
@ -36,9 +38,8 @@
|
||||
|
||||
#include <meta/main.h>
|
||||
#include <meta/errors.h>
|
||||
#include "monitor-private.h"
|
||||
|
||||
#include "edid.h"
|
||||
#include "meta-monitor-config.h"
|
||||
|
||||
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
|
||||
|
||||
@ -1017,7 +1018,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
|
||||
MetaOutput *old_outputs;
|
||||
MetaCRTC *old_crtcs;
|
||||
MetaMonitorMode *old_modes;
|
||||
int n_old_outputs;
|
||||
unsigned int n_old_outputs, n_old_modes;
|
||||
gboolean new_config;
|
||||
|
||||
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
|
||||
@ -1029,6 +1030,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
|
||||
old_outputs = manager->outputs;
|
||||
n_old_outputs = manager->n_outputs;
|
||||
old_modes = manager->modes;
|
||||
n_old_modes = manager->n_modes;
|
||||
old_crtcs = manager->crtcs;
|
||||
|
||||
manager->serial++;
|
||||
@ -1068,7 +1070,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
|
||||
}
|
||||
|
||||
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
|
||||
g_free (old_modes);
|
||||
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
|
||||
g_free (old_crtcs);
|
||||
|
||||
return TRUE;
|
40
src/backends/x11/meta-monitor-manager-xrandr.h
Normal file
40
src/backends/x11/meta-monitor-manager-xrandr.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2003 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_MONITOR_MANAGER_XRANDR_H
|
||||
#define META_MONITOR_MANAGER_XRANDR_H
|
||||
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
#define META_TYPE_MONITOR_MANAGER_XRANDR (meta_monitor_manager_xrandr_get_type ())
|
||||
#define META_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandr))
|
||||
#define META_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
|
||||
#define META_IS_MONITOR_MANAGER_XRANDR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_XRANDR))
|
||||
#define META_IS_MONITOR_MANAGER_XRANDR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_XRANDR))
|
||||
#define META_MONITOR_MANAGER_XRANDR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_XRANDR, MetaMonitorManagerXrandrClass))
|
||||
|
||||
typedef struct _MetaMonitorManagerXrandrClass MetaMonitorManagerXrandrClass;
|
||||
typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
|
||||
|
||||
GType meta_monitor_manager_xrandr_get_type (void);
|
||||
|
||||
#endif /* META_MONITOR_MANAGER_XRANDR_H */
|
@ -11,35 +11,21 @@
|
||||
#include "meta-window-actor-private.h"
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
typedef struct _MetaCompScreen MetaCompScreen;
|
||||
|
||||
struct _MetaCompositor
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
guint repaint_func_id;
|
||||
|
||||
ClutterActor *shadow_src;
|
||||
|
||||
MetaPlugin *modal_plugin;
|
||||
|
||||
gint64 server_time_query_time;
|
||||
gint64 server_time_offset;
|
||||
|
||||
guint server_time_is_monotonic_time : 1;
|
||||
guint show_redraw : 1;
|
||||
guint debug : 1;
|
||||
guint no_mipmaps : 1;
|
||||
};
|
||||
|
||||
struct _MetaCompScreen
|
||||
{
|
||||
MetaScreen *screen;
|
||||
|
||||
ClutterActor *stage, *window_group, *top_window_group, *overlay_group;
|
||||
ClutterActor *stage, *window_group, *top_window_group;
|
||||
ClutterActor *background_actor;
|
||||
GList *windows;
|
||||
GHashTable *windows_by_xid;
|
||||
Window output;
|
||||
|
||||
CoglOnscreen *onscreen;
|
||||
@ -57,19 +43,17 @@ struct _MetaCompScreen
|
||||
/* Wait 2ms after vblank before starting to draw next frame */
|
||||
#define META_SYNC_DELAY 2
|
||||
|
||||
void meta_switch_workspace_completed (MetaScreen *screen);
|
||||
void meta_switch_workspace_completed (MetaCompositor *compositor);
|
||||
|
||||
gboolean meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
gboolean meta_begin_modal_for_plugin (MetaCompositor *compositor,
|
||||
MetaPlugin *plugin,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp);
|
||||
void meta_end_modal_for_plugin (MetaScreen *screen,
|
||||
void meta_end_modal_for_plugin (MetaCompositor *compositor,
|
||||
MetaPlugin *plugin,
|
||||
guint32 timestamp);
|
||||
|
||||
gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
|
||||
gint64 monotonic_time);
|
||||
|
||||
void meta_check_end_modal (MetaScreen *screen);
|
||||
|
||||
#endif /* META_COMPOSITOR_PRIVATE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,8 +26,6 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <cogl/cogl-texture-pixmap-x11.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "cogl-utils.h"
|
||||
@ -755,88 +753,6 @@ set_filename (MetaBackground *self,
|
||||
priv->filename = g_strdup (filename);
|
||||
}
|
||||
|
||||
static Pixmap
|
||||
get_still_frame_for_monitor (MetaScreen *screen,
|
||||
int monitor)
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xroot = meta_screen_get_xroot (screen);
|
||||
Pixmap pixmap;
|
||||
GC gc;
|
||||
XGCValues values;
|
||||
MetaRectangle geometry;
|
||||
int depth;
|
||||
|
||||
meta_screen_get_monitor_geometry (screen, monitor, &geometry);
|
||||
|
||||
depth = DefaultDepth (xdisplay, meta_screen_get_screen_number (screen));
|
||||
|
||||
pixmap = XCreatePixmap (xdisplay,
|
||||
xroot,
|
||||
geometry.width, geometry.height, depth);
|
||||
|
||||
values.function = GXcopy;
|
||||
values.plane_mask = AllPlanes;
|
||||
values.fill_style = FillSolid;
|
||||
values.subwindow_mode = IncludeInferiors;
|
||||
|
||||
gc = XCreateGC (xdisplay,
|
||||
xroot,
|
||||
GCFunction | GCPlaneMask | GCFillStyle | GCSubwindowMode,
|
||||
&values);
|
||||
|
||||
XCopyArea (xdisplay,
|
||||
xroot, pixmap, gc,
|
||||
geometry.x, geometry.y,
|
||||
geometry.width, geometry.height,
|
||||
0, 0);
|
||||
|
||||
XFreeGC (xdisplay, gc);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_load_still_frame:
|
||||
* @self: the #MetaBackground
|
||||
*
|
||||
* Takes a screenshot of the desktop and uses it as the background
|
||||
* source.
|
||||
*/
|
||||
void
|
||||
meta_background_load_still_frame (MetaBackground *self)
|
||||
{
|
||||
MetaBackgroundPrivate *priv = self->priv;
|
||||
MetaDisplay *display = meta_screen_get_display (priv->screen);
|
||||
Pixmap still_frame;
|
||||
CoglTexture *texture;
|
||||
CoglContext *context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
GError *error = NULL;
|
||||
|
||||
ensure_pipeline (self);
|
||||
|
||||
unset_texture (self);
|
||||
set_style (self, G_DESKTOP_BACKGROUND_STYLE_STRETCHED);
|
||||
|
||||
still_frame = get_still_frame_for_monitor (priv->screen, priv->monitor);
|
||||
XSync (meta_display_get_xdisplay (display), False);
|
||||
|
||||
meta_error_trap_push (display);
|
||||
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (context, still_frame, FALSE, &error));
|
||||
meta_error_trap_pop (display);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to create background texture from pixmap: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
set_texture (self, texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_load_gradient:
|
||||
* @self: the #MetaBackground
|
||||
|
@ -37,7 +37,7 @@ static GType plugin_type = G_TYPE_NONE;
|
||||
|
||||
struct MetaPluginManager
|
||||
{
|
||||
MetaScreen *screen;
|
||||
MetaCompositor *compositor;
|
||||
MetaPlugin *plugin;
|
||||
};
|
||||
|
||||
@ -91,7 +91,7 @@ on_confirm_display_change (MetaMonitorManager *monitors,
|
||||
}
|
||||
|
||||
MetaPluginManager *
|
||||
meta_plugin_manager_new (MetaScreen *screen)
|
||||
meta_plugin_manager_new (MetaCompositor *compositor)
|
||||
{
|
||||
MetaPluginManager *plugin_mgr;
|
||||
MetaPluginClass *klass;
|
||||
@ -99,8 +99,10 @@ meta_plugin_manager_new (MetaScreen *screen)
|
||||
MetaMonitorManager *monitors;
|
||||
|
||||
plugin_mgr = g_new0 (MetaPluginManager, 1);
|
||||
plugin_mgr->screen = screen;
|
||||
plugin_mgr->plugin = plugin = g_object_new (plugin_type, "screen", screen, NULL);
|
||||
plugin_mgr->compositor = compositor;
|
||||
plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL);
|
||||
|
||||
_meta_plugin_set_compositor (plugin, compositor);
|
||||
|
||||
klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
|
||||
@ -151,7 +153,7 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
|
||||
MetaDisplay *display = plugin_mgr->compositor->display;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
if (display->display_opening)
|
||||
@ -165,8 +167,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->minimize (plugin, actor);
|
||||
}
|
||||
break;
|
||||
@ -176,8 +176,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->map (plugin, actor);
|
||||
}
|
||||
break;
|
||||
@ -185,7 +183,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
if (klass->destroy)
|
||||
{
|
||||
retval = TRUE;
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->destroy (plugin, actor);
|
||||
}
|
||||
break;
|
||||
@ -216,7 +213,7 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
|
||||
MetaDisplay *display = plugin_mgr->compositor->display;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
if (display->display_opening)
|
||||
@ -230,8 +227,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->maximize (plugin, actor,
|
||||
target_x, target_y,
|
||||
target_width, target_height);
|
||||
@ -243,8 +238,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->unmaximize (plugin, actor,
|
||||
target_x, target_y,
|
||||
target_width, target_height);
|
||||
@ -273,7 +266,7 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
|
||||
MetaDisplay *display = plugin_mgr->compositor->display;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
if (display->display_opening)
|
||||
@ -283,8 +276,6 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
|
||||
{
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_switch_workspace (plugin_mgr);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->switch_workspace (plugin, from, to, direction);
|
||||
}
|
||||
|
||||
@ -333,7 +324,7 @@ meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr,
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
|
||||
MetaDisplay *display = plugin_mgr->compositor->display;
|
||||
|
||||
if (display->display_opening)
|
||||
return FALSE;
|
||||
@ -352,7 +343,7 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
|
||||
{
|
||||
MetaPlugin *plugin = plugin_mgr->plugin;
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
|
||||
MetaDisplay *display = plugin_mgr->compositor->display;
|
||||
|
||||
if (display->display_opening)
|
||||
return FALSE;
|
||||
|
@ -44,7 +44,7 @@
|
||||
*/
|
||||
typedef struct MetaPluginManager MetaPluginManager;
|
||||
|
||||
MetaPluginManager * meta_plugin_manager_new (MetaScreen *screen);
|
||||
MetaPluginManager * meta_plugin_manager_new (MetaCompositor *compositor);
|
||||
|
||||
void meta_plugin_manager_load (const gchar *plugin_name);
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "meta-plugin-manager.h"
|
||||
#include <meta/screen.h>
|
||||
#include <meta/display.h>
|
||||
#include <meta/util.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <X11/Xlib.h>
|
||||
@ -39,98 +40,22 @@
|
||||
|
||||
#include "compositor-private.h"
|
||||
#include "meta-window-actor-private.h"
|
||||
#include "monitor-private.h"
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
|
||||
|
||||
#define META_PLUGIN_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate))
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SCREEN,
|
||||
PROP_DEBUG_MODE,
|
||||
};
|
||||
|
||||
struct _MetaPluginPrivate
|
||||
{
|
||||
MetaScreen *screen;
|
||||
|
||||
gint running;
|
||||
gboolean debug : 1;
|
||||
MetaCompositor *compositor;
|
||||
};
|
||||
|
||||
static void
|
||||
meta_plugin_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCREEN:
|
||||
priv->screen = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_DEBUG_MODE:
|
||||
priv->debug = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_plugin_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCREEN:
|
||||
g_value_set_object (value, priv->screen);
|
||||
break;
|
||||
case PROP_DEBUG_MODE:
|
||||
g_value_set_boolean (value, priv->debug);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
meta_plugin_class_init (MetaPluginClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = meta_plugin_set_property;
|
||||
gobject_class->get_property = meta_plugin_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SCREEN,
|
||||
g_param_spec_object ("screen",
|
||||
"MetaScreen",
|
||||
"MetaScreen",
|
||||
META_TYPE_SCREEN,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DEBUG_MODE,
|
||||
g_param_spec_boolean ("debug-mode",
|
||||
"Debug Mode",
|
||||
"Debug Mode",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate));
|
||||
g_type_class_add_private (klass, sizeof (MetaPluginPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -139,22 +64,6 @@ meta_plugin_init (MetaPlugin *self)
|
||||
self->priv = META_PLUGIN_GET_PRIVATE (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_plugin_running (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return (priv->running > 0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_plugin_debug_mode (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return priv->debug;
|
||||
}
|
||||
|
||||
const MetaPluginInfo *
|
||||
meta_plugin_get_info (MetaPlugin *plugin)
|
||||
{
|
||||
@ -166,31 +75,26 @@ meta_plugin_get_info (MetaPlugin *plugin)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _meta_plugin_effect_started:
|
||||
* @plugin: the plugin
|
||||
*
|
||||
* Mark that an effect has started for the plugin. This is called
|
||||
* internally by MetaPluginManager.
|
||||
*/
|
||||
void
|
||||
_meta_plugin_effect_started (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
priv->running++;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_meta_plugin_xevent_filter (MetaPlugin *plugin,
|
||||
XEvent *xev)
|
||||
{
|
||||
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
|
||||
/* 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
|
||||
else if (!meta_is_wayland_compositor ())
|
||||
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -198,15 +102,7 @@ meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
MetaScreen *screen = priv->screen;
|
||||
|
||||
if (priv->running-- < 0)
|
||||
{
|
||||
g_warning ("Error in running effect accounting, adjusting.");
|
||||
priv->running = 0;
|
||||
}
|
||||
|
||||
meta_switch_workspace_completed (screen);
|
||||
meta_switch_workspace_completed (priv->compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -214,26 +110,6 @@ meta_plugin_window_effect_completed (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor,
|
||||
unsigned long event)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
if (priv->running-- < 0)
|
||||
{
|
||||
g_warning ("Error in running effect accounting, adjusting.");
|
||||
priv->running = 0;
|
||||
}
|
||||
|
||||
if (!actor)
|
||||
{
|
||||
const MetaPluginInfo *info;
|
||||
const gchar *name = NULL;
|
||||
|
||||
if (plugin && (info = meta_plugin_get_info (plugin)))
|
||||
name = info->name;
|
||||
|
||||
g_warning ("Plugin [%s] passed NULL for actor!",
|
||||
name ? name : "unknown");
|
||||
}
|
||||
|
||||
meta_window_actor_effect_completed (actor, event);
|
||||
}
|
||||
|
||||
@ -300,7 +176,7 @@ meta_plugin_begin_modal (MetaPlugin *plugin,
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return meta_begin_modal_for_plugin (priv->screen, plugin,
|
||||
return meta_begin_modal_for_plugin (priv->compositor, plugin,
|
||||
options, timestamp);
|
||||
}
|
||||
|
||||
@ -321,16 +197,14 @@ meta_plugin_end_modal (MetaPlugin *plugin,
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
meta_end_modal_for_plugin (priv->screen, plugin, timestamp);
|
||||
meta_end_modal_for_plugin (priv->compositor, plugin, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_plugin_get_screen:
|
||||
* @plugin: a #MetaPlugin
|
||||
*
|
||||
* Gets the #MetaScreen corresponding to a plugin. Each plugin instance
|
||||
* is associated with exactly one screen; if Metacity is managing
|
||||
* multiple screens, multiple plugin instances will be created.
|
||||
* Gets the #MetaScreen corresponding to a plugin.
|
||||
*
|
||||
* Return value: (transfer none): the #MetaScreen for the plugin
|
||||
*/
|
||||
@ -339,7 +213,15 @@ meta_plugin_get_screen (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return priv->screen;
|
||||
return priv->compositor->display->screen;
|
||||
}
|
||||
|
||||
void
|
||||
_meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
priv->compositor = compositor;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
#include <meta/util.h>
|
||||
#include "clutter-utils.h"
|
||||
#include "meta-texture-tower.h"
|
||||
|
||||
@ -42,8 +43,6 @@
|
||||
static void meta_shaped_texture_dispose (GObject *object);
|
||||
|
||||
static void meta_shaped_texture_paint (ClutterActor *actor);
|
||||
static void meta_shaped_texture_pick (ClutterActor *actor,
|
||||
const ClutterColor *color);
|
||||
|
||||
static void meta_shaped_texture_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
@ -73,8 +72,6 @@ struct _MetaShapedTexturePrivate
|
||||
CoglTexture *texture;
|
||||
CoglTexture *mask_texture;
|
||||
|
||||
cairo_region_t *input_shape_region;
|
||||
|
||||
/* The region containing only fully opaque pixels */
|
||||
cairo_region_t *opaque_region;
|
||||
|
||||
@ -98,7 +95,6 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
|
||||
actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width;
|
||||
actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height;
|
||||
actor_class->paint = meta_shaped_texture_paint;
|
||||
actor_class->pick = meta_shaped_texture_pick;
|
||||
actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
|
||||
@ -232,6 +228,54 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||
&coords[0], 8);
|
||||
}
|
||||
|
||||
static void
|
||||
set_cogl_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *cogl_tex)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
guint width, height;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture)
|
||||
cogl_object_unref (priv->texture);
|
||||
|
||||
priv->texture = cogl_tex;
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
{
|
||||
cogl_object_ref (cogl_tex);
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (width != priv->tex_width ||
|
||||
height != priv->tex_height)
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* size changed to 0 going to an invalid handle */
|
||||
priv->tex_width = 0;
|
||||
priv->tex_height = 0;
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
/* NB: We don't queue a redraw of the actor here because we don't
|
||||
* know how much of the buffer has changed with respect to the
|
||||
* previous buffer. We only queue a redraw in response to surface
|
||||
* damage. */
|
||||
|
||||
if (priv->create_mipmaps)
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_paint (ClutterActor *actor)
|
||||
{
|
||||
@ -415,71 +459,6 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
cairo_region_destroy (blended_region);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_pick (ClutterActor *actor,
|
||||
const ClutterColor *color)
|
||||
{
|
||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
|
||||
if (!clutter_actor_should_pick_paint (actor) ||
|
||||
(priv->clip_region && cairo_region_is_empty (priv->clip_region)))
|
||||
return;
|
||||
|
||||
/* If there is no region then use the regular pick */
|
||||
if (priv->input_shape_region == NULL)
|
||||
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color);
|
||||
else
|
||||
{
|
||||
int n_rects;
|
||||
float *rectangles;
|
||||
int i;
|
||||
CoglPipeline *pipeline;
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglColor cogl_color;
|
||||
|
||||
/* Note: We don't bother trying to intersect the pick and clip regions
|
||||
* since needing to copy the region, do the intersection, and probably
|
||||
* increase the number of rectangles seems more likely to have a negative
|
||||
* effect.
|
||||
*
|
||||
* NB: Most of the time when just using rectangles for picking then
|
||||
* picking shouldn't involve any rendering, and minimizing the number of
|
||||
* rectangles has more benefit than reducing the area of the pick
|
||||
* region.
|
||||
*/
|
||||
|
||||
n_rects = cairo_region_num_rectangles (priv->input_shape_region);
|
||||
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
int pos = i * 4;
|
||||
|
||||
cairo_region_get_rectangle (priv->input_shape_region, i, &rect);
|
||||
|
||||
rectangles[pos] = rect.x;
|
||||
rectangles[pos + 1] = rect.y;
|
||||
rectangles[pos + 2] = rect.x + rect.width;
|
||||
rectangles[pos + 3] = rect.y + rect.height;
|
||||
}
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
|
||||
|
||||
pipeline = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_color (pipeline, &cogl_color);
|
||||
|
||||
cogl_framebuffer_draw_rectangles (fb, pipeline,
|
||||
rectangles, n_rects);
|
||||
cogl_object_unref (pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
@ -699,53 +678,6 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_cogl_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *cogl_tex)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
guint width, height;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->texture != NULL)
|
||||
cogl_object_unref (priv->texture);
|
||||
|
||||
priv->texture = cogl_tex;
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
{
|
||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
||||
|
||||
if (width != priv->tex_width ||
|
||||
height != priv->tex_height)
|
||||
{
|
||||
priv->tex_width = width;
|
||||
priv->tex_height = height;
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* size changed to 0 going to an invalid texture */
|
||||
priv->tex_width = 0;
|
||||
priv->tex_height = 0;
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
/* NB: We don't queue a redraw of the actor here because we don't
|
||||
* know how much of the buffer has changed with respect to the
|
||||
* previous buffer. We only queue a redraw in response to surface
|
||||
* damage. */
|
||||
|
||||
if (priv->create_mipmaps)
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_texture:
|
||||
* @stex: The #MetaShapedTexture
|
||||
@ -773,41 +705,6 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex)
|
||||
return COGL_TEXTURE (stex->priv->texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_input_shape_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
* @shape_region: the region of the texture that should respond to
|
||||
* input.
|
||||
*
|
||||
* Determines what region of the texture should accept input. For
|
||||
* X based windows this is defined by the ShapeInput region of the
|
||||
* window.
|
||||
*/
|
||||
void
|
||||
meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
|
||||
cairo_region_t *shape_region)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
priv = stex->priv;
|
||||
|
||||
if (priv->input_shape_region != NULL)
|
||||
{
|
||||
cairo_region_destroy (priv->input_shape_region);
|
||||
priv->input_shape_region = NULL;
|
||||
}
|
||||
|
||||
if (shape_region != NULL)
|
||||
{
|
||||
cairo_region_reference (shape_region);
|
||||
priv->input_shape_region = shape_region;
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_shaped_texture_set_opaque_region:
|
||||
* @stex: a #MetaShapedTexture
|
||||
|
195
src/compositor/meta-surface-actor-wayland.c
Normal file
195
src/compositor/meta-surface-actor-wayland.c
Normal file
@ -0,0 +1,195 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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-surface-actor-wayland.h"
|
||||
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#include "meta-shaped-texture-private.h"
|
||||
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
|
||||
struct _MetaSurfaceActorWaylandPrivate
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_listener buffer_destroy_listener;
|
||||
};
|
||||
typedef struct _MetaSurfaceActorWaylandPrivate MetaSurfaceActorWaylandPrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorWayland, meta_surface_actor_wayland, META_TYPE_SURFACE_ACTOR)
|
||||
|
||||
static void
|
||||
meta_surface_actor_handle_buffer_destroy (struct wl_listener *listener, void *data)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = wl_container_of (listener, priv, buffer_destroy_listener);
|
||||
|
||||
/* If the buffer is destroyed while we're attached to it,
|
||||
* we want to unset priv->buffer so we don't access freed
|
||||
* memory. Keep the texture set however so the user doesn't
|
||||
* see the window disappear. */
|
||||
priv->buffer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
|
||||
if (priv->buffer)
|
||||
{
|
||||
struct wl_resource *resource = priv->buffer->resource;
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (resource);
|
||||
|
||||
if (shm_buffer)
|
||||
{
|
||||
CoglTexture2D *texture = COGL_TEXTURE_2D (priv->buffer->texture);
|
||||
cogl_wayland_texture_set_region_from_shm_buffer (texture, x, y, width, height, shm_buffer, x, y, 0, NULL);
|
||||
}
|
||||
|
||||
meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_surface_actor_wayland_is_visible (MetaSurfaceActor *actor)
|
||||
{
|
||||
/* TODO: ensure that the buffer isn't NULL, implement
|
||||
* wayland mapping semantics */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_surface_actor_wayland_should_unredirect (MetaSurfaceActor *actor)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_set_unredirected (MetaSurfaceActor *actor,
|
||||
gboolean unredirected)
|
||||
{
|
||||
/* Do nothing. In the future, we'll use KMS to set this
|
||||
* up as a hardware overlay or something. */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static MetaWindow *
|
||||
meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (META_SURFACE_ACTOR_WAYLAND (actor));
|
||||
|
||||
return priv->surface->window;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_dispose (GObject *object)
|
||||
{
|
||||
MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object);
|
||||
|
||||
meta_surface_actor_wayland_set_buffer (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
|
||||
{
|
||||
MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
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;
|
||||
|
||||
surface_actor_class->should_unredirect = meta_surface_actor_wayland_should_unredirect;
|
||||
surface_actor_class->set_unredirected = meta_surface_actor_wayland_set_unredirected;
|
||||
surface_actor_class->is_unredirected = meta_surface_actor_wayland_is_unredirected;
|
||||
|
||||
surface_actor_class->get_window = meta_surface_actor_wayland_get_window;
|
||||
|
||||
object_class->dispose = meta_surface_actor_wayland_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_wayland_init (MetaSurfaceActorWayland *self)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
|
||||
priv->buffer_destroy_listener.notify = meta_surface_actor_handle_buffer_destroy;
|
||||
}
|
||||
|
||||
MetaSurfaceActor *
|
||||
meta_surface_actor_wayland_new (MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaSurfaceActorWayland *self = g_object_new (META_TYPE_SURFACE_ACTOR_WAYLAND, NULL);
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
priv->surface = surface;
|
||||
|
||||
return META_SURFACE_ACTOR (self);
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
|
||||
MetaWaylandBuffer *buffer)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||
|
||||
if (priv->buffer)
|
||||
wl_list_remove (&priv->buffer_destroy_listener.link);
|
||||
|
||||
priv->buffer = buffer;
|
||||
|
||||
if (priv->buffer)
|
||||
{
|
||||
wl_signal_add (&priv->buffer->destroy_signal, &priv->buffer_destroy_listener);
|
||||
meta_shaped_texture_set_texture (stex, priv->buffer->texture);
|
||||
}
|
||||
else
|
||||
meta_shaped_texture_set_texture (stex, NULL);
|
||||
}
|
||||
|
||||
MetaWaylandSurface *
|
||||
meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self)
|
||||
{
|
||||
MetaSurfaceActorWaylandPrivate *priv = meta_surface_actor_wayland_get_instance_private (self);
|
||||
return priv->surface;
|
||||
}
|
66
src/compositor/meta-surface-actor-wayland.h
Normal file
66
src/compositor/meta-surface-actor-wayland.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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_SURFACE_ACTOR_WAYLAND_H__
|
||||
#define __META_SURFACE_ACTOR_WAYLAND_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
#include "wayland/meta-wayland.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_SURFACE_ACTOR_WAYLAND (meta_surface_actor_wayland_get_type ())
|
||||
#define META_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWayland))
|
||||
#define META_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass))
|
||||
#define META_IS_SURFACE_ACTOR_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND))
|
||||
#define META_IS_SURFACE_ACTOR_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_WAYLAND))
|
||||
#define META_SURFACE_ACTOR_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_WAYLAND, MetaSurfaceActorWaylandClass))
|
||||
|
||||
typedef struct _MetaSurfaceActorWayland MetaSurfaceActorWayland;
|
||||
typedef struct _MetaSurfaceActorWaylandClass MetaSurfaceActorWaylandClass;
|
||||
|
||||
struct _MetaSurfaceActorWayland
|
||||
{
|
||||
MetaSurfaceActor parent;
|
||||
};
|
||||
|
||||
struct _MetaSurfaceActorWaylandClass
|
||||
{
|
||||
MetaSurfaceActorClass parent_class;
|
||||
};
|
||||
|
||||
GType meta_surface_actor_wayland_get_type (void);
|
||||
|
||||
MetaSurfaceActor * meta_surface_actor_wayland_new (MetaWaylandSurface *surface);
|
||||
MetaWaylandSurface * meta_surface_actor_wayland_get_surface (MetaSurfaceActorWayland *self);
|
||||
|
||||
void meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
|
||||
MetaWaylandBuffer *buffer);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */
|
459
src/compositor/meta-surface-actor-x11.c
Normal file
459
src/compositor/meta-surface-actor-x11.c
Normal file
@ -0,0 +1,459 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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:
|
||||
* Owen Taylor <otaylor@redhat.com>
|
||||
* Jasper St. Pierre <jstpierre@mecheye.net>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-surface-actor-x11.h"
|
||||
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#include <cogl/cogl-texture-pixmap-x11.h>
|
||||
|
||||
#include <meta/errors.h>
|
||||
#include "window-private.h"
|
||||
#include "meta-shaped-texture-private.h"
|
||||
#include "meta-cullable.h"
|
||||
|
||||
struct _MetaSurfaceActorX11Private
|
||||
{
|
||||
MetaWindow *window;
|
||||
|
||||
MetaDisplay *display;
|
||||
|
||||
CoglTexture *texture;
|
||||
Pixmap pixmap;
|
||||
Damage damage;
|
||||
|
||||
int last_width;
|
||||
int last_height;
|
||||
|
||||
/* This is used to detect fullscreen windows that need to be unredirected */
|
||||
guint full_damage_frames_count;
|
||||
guint does_full_damage : 1;
|
||||
|
||||
/* Other state... */
|
||||
guint received_damage : 1;
|
||||
guint size_changed : 1;
|
||||
|
||||
guint unredirected : 1;
|
||||
};
|
||||
typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaSurfaceActorX11, meta_surface_actor_x11, META_TYPE_SURFACE_ACTOR)
|
||||
|
||||
static void
|
||||
free_damage (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
MetaDisplay *display = priv->display;
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
if (priv->damage == None)
|
||||
return;
|
||||
|
||||
meta_error_trap_push (display);
|
||||
XDamageDestroy (xdisplay, priv->damage);
|
||||
priv->damage = None;
|
||||
meta_error_trap_pop (display);
|
||||
}
|
||||
|
||||
static void
|
||||
detach_pixmap (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
MetaDisplay *display = priv->display;
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||
|
||||
if (priv->pixmap == None)
|
||||
return;
|
||||
|
||||
/* Get rid of all references to the pixmap before freeing it; it's unclear whether
|
||||
* you are supposed to be able to free a GLXPixmap after freeing the underlying
|
||||
* pixmap, but it certainly doesn't work with current DRI/Mesa
|
||||
*/
|
||||
meta_shaped_texture_set_texture (stex, NULL);
|
||||
cogl_flush ();
|
||||
|
||||
meta_error_trap_push (display);
|
||||
XFreePixmap (xdisplay, priv->pixmap);
|
||||
priv->pixmap = None;
|
||||
meta_error_trap_pop (display);
|
||||
|
||||
cogl_object_unref (priv->texture);
|
||||
priv->texture = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_pixmap (MetaSurfaceActorX11 *self,
|
||||
Pixmap pixmap)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||
CoglTexture *texture;
|
||||
|
||||
g_assert (priv->pixmap == None);
|
||||
priv->pixmap = pixmap;
|
||||
|
||||
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, NULL));
|
||||
|
||||
if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
|
||||
g_warning ("NOTE: Not using GLX TFP!\n");
|
||||
|
||||
priv->texture = texture;
|
||||
meta_shaped_texture_set_texture (stex, texture);
|
||||
}
|
||||
|
||||
static void
|
||||
update_pixmap (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
MetaDisplay *display = priv->display;
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
if (priv->size_changed)
|
||||
{
|
||||
detach_pixmap (self);
|
||||
priv->size_changed = FALSE;
|
||||
}
|
||||
|
||||
if (priv->pixmap == None)
|
||||
{
|
||||
Pixmap new_pixmap;
|
||||
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
|
||||
|
||||
meta_error_trap_push (display);
|
||||
new_pixmap = XCompositeNameWindowPixmap (xdisplay, xwindow);
|
||||
|
||||
if (meta_error_trap_pop_with_return (display) != Success)
|
||||
{
|
||||
/* Probably a BadMatch if the window isn't viewable; we could
|
||||
* GrabServer/GetWindowAttributes/NameWindowPixmap/UngrabServer/Sync
|
||||
* to avoid this, but there's no reason to take two round trips
|
||||
* when one will do. (We need that Sync if we want to handle failures
|
||||
* for any reason other than !viewable. That's unlikely, but maybe
|
||||
* we'll BadAlloc or something.)
|
||||
*/
|
||||
new_pixmap = None;
|
||||
}
|
||||
|
||||
if (new_pixmap == None)
|
||||
{
|
||||
meta_verbose ("Unable to get named pixmap for %s\n",
|
||||
meta_window_get_description (priv->window));
|
||||
return;
|
||||
}
|
||||
|
||||
set_pixmap (self, new_pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_visible (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
return (priv->pixmap != None) && !priv->unredirected;
|
||||
}
|
||||
|
||||
static void
|
||||
damage_area (MetaSurfaceActorX11 *self,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
if (!is_visible (self))
|
||||
return;
|
||||
|
||||
cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height);
|
||||
meta_surface_actor_update_area (META_SURFACE_ACTOR (self), x, y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_process_damage (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
priv->received_damage = TRUE;
|
||||
|
||||
if (meta_window_is_fullscreen (priv->window) && !priv->unredirected && !priv->does_full_damage)
|
||||
{
|
||||
MetaRectangle window_rect;
|
||||
meta_window_get_frame_rect (priv->window, &window_rect);
|
||||
|
||||
if (window_rect.x == x &&
|
||||
window_rect.y == y &&
|
||||
window_rect.width == width &&
|
||||
window_rect.height == height)
|
||||
priv->full_damage_frames_count++;
|
||||
else
|
||||
priv->full_damage_frames_count = 0;
|
||||
|
||||
if (priv->full_damage_frames_count >= 100)
|
||||
priv->does_full_damage = TRUE;
|
||||
}
|
||||
|
||||
/* Drop damage event for unredirected windows */
|
||||
if (priv->unredirected)
|
||||
return;
|
||||
|
||||
damage_area (self, x, y, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
MetaDisplay *display = priv->display;
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
if (priv->received_damage)
|
||||
{
|
||||
meta_error_trap_push (display);
|
||||
XDamageSubtract (xdisplay, priv->damage, None, None);
|
||||
meta_error_trap_pop (display);
|
||||
|
||||
/* We need to make sure that any X drawing that happens before the
|
||||
* XDamageSubtract() above is visible to subsequent GL rendering;
|
||||
* the only standardized way to do this is EXT_x11_sync_object,
|
||||
* which isn't yet widely available. For now, we count on details
|
||||
* of Xorg and the open source drivers, and hope for the best
|
||||
* otherwise.
|
||||
*
|
||||
* Xorg and open source driver specifics:
|
||||
*
|
||||
* The X server makes sure to flush drawing to the kernel before
|
||||
* sending out damage events, but since we use DamageReportBoundingBox
|
||||
* there may be drawing between the last damage event and the
|
||||
* XDamageSubtract() that needs to be flushed as well.
|
||||
*
|
||||
* Xorg always makes sure that drawing is flushed to the kernel
|
||||
* before writing events or responses to the client, so any round trip
|
||||
* request at this point is sufficient to flush the GLX buffers.
|
||||
*/
|
||||
XSync (xdisplay, False);
|
||||
|
||||
priv->received_damage = FALSE;
|
||||
}
|
||||
|
||||
update_pixmap (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_surface_actor_x11_is_visible (MetaSurfaceActor *actor)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
|
||||
return is_visible (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_surface_actor_x11_should_unredirect (MetaSurfaceActor *actor)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
MetaWindow *window = priv->window;
|
||||
|
||||
if (meta_window_requested_dont_bypass_compositor (window))
|
||||
return FALSE;
|
||||
|
||||
if (window->opacity != 0xFF)
|
||||
return FALSE;
|
||||
|
||||
if (window->shape_region != NULL)
|
||||
return FALSE;
|
||||
|
||||
if (meta_surface_actor_is_argb32 (actor) && !meta_window_requested_bypass_compositor (window))
|
||||
return FALSE;
|
||||
|
||||
if (!meta_window_is_monitor_sized (window))
|
||||
return FALSE;
|
||||
|
||||
if (meta_window_requested_bypass_compositor (window))
|
||||
return TRUE;
|
||||
|
||||
if (meta_window_is_override_redirect (window))
|
||||
return TRUE;
|
||||
|
||||
if (priv->does_full_damage)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
sync_unredirected (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
MetaDisplay *display = priv->display;
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
|
||||
|
||||
meta_error_trap_push (display);
|
||||
|
||||
if (priv->unredirected)
|
||||
{
|
||||
detach_pixmap (self);
|
||||
XCompositeUnredirectWindow (xdisplay, xwindow, CompositeRedirectManual);
|
||||
}
|
||||
else
|
||||
{
|
||||
XCompositeRedirectWindow (xdisplay, xwindow, CompositeRedirectManual);
|
||||
}
|
||||
|
||||
meta_error_trap_pop (display);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_set_unredirected (MetaSurfaceActor *actor,
|
||||
gboolean unredirected)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
if (priv->unredirected == unredirected)
|
||||
return;
|
||||
|
||||
priv->unredirected = unredirected;
|
||||
sync_unredirected (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_surface_actor_x11_is_unredirected (MetaSurfaceActor *actor)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
return priv->unredirected;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_dispose (GObject *object)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (object);
|
||||
|
||||
detach_pixmap (self);
|
||||
free_damage (self);
|
||||
|
||||
G_OBJECT_CLASS (meta_surface_actor_x11_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static MetaWindow *
|
||||
meta_surface_actor_x11_get_window (MetaSurfaceActor *actor)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (META_SURFACE_ACTOR_X11 (actor));
|
||||
|
||||
return priv->window;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MetaSurfaceActorClass *surface_actor_class = META_SURFACE_ACTOR_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_surface_actor_x11_dispose;
|
||||
|
||||
surface_actor_class->process_damage = meta_surface_actor_x11_process_damage;
|
||||
surface_actor_class->pre_paint = meta_surface_actor_x11_pre_paint;
|
||||
surface_actor_class->is_visible = meta_surface_actor_x11_is_visible;
|
||||
|
||||
surface_actor_class->should_unredirect = meta_surface_actor_x11_should_unredirect;
|
||||
surface_actor_class->set_unredirected = meta_surface_actor_x11_set_unredirected;
|
||||
surface_actor_class->is_unredirected = meta_surface_actor_x11_is_unredirected;
|
||||
|
||||
surface_actor_class->get_window = meta_surface_actor_x11_get_window;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_x11_init (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
priv->last_width = -1;
|
||||
priv->last_height = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
create_damage (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
Display *xdisplay = meta_display_get_xdisplay (priv->display);
|
||||
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
|
||||
|
||||
priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox);
|
||||
}
|
||||
|
||||
static void
|
||||
window_decorated_notify (MetaWindow *window,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
|
||||
|
||||
free_damage (self);
|
||||
create_damage (self);
|
||||
}
|
||||
|
||||
MetaSurfaceActor *
|
||||
meta_surface_actor_x11_new (MetaWindow *window)
|
||||
{
|
||||
MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
MetaDisplay *display = meta_window_get_display (window);
|
||||
|
||||
g_assert (!meta_is_wayland_compositor ());
|
||||
|
||||
priv->window = window;
|
||||
priv->display = display;
|
||||
|
||||
create_damage (self);
|
||||
g_signal_connect_object (priv->window, "notify::decorated",
|
||||
G_CALLBACK (window_decorated_notify), self, 0);
|
||||
|
||||
priv->unredirected = FALSE;
|
||||
sync_unredirected (self);
|
||||
|
||||
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
|
||||
return META_SURFACE_ACTOR (self);
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
|
||||
int width, int height)
|
||||
{
|
||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||
|
||||
if (priv->last_width == width &&
|
||||
priv->last_height == height)
|
||||
return;
|
||||
|
||||
priv->size_changed = TRUE;
|
||||
priv->last_width = width;
|
||||
priv->last_height = height;
|
||||
}
|
69
src/compositor/meta-surface-actor-x11.h
Normal file
69
src/compositor/meta-surface-actor-x11.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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:
|
||||
* Owen Taylor <otaylor@redhat.com>
|
||||
* Jasper St. Pierre <jstpierre@mecheye.net>
|
||||
*/
|
||||
|
||||
#ifndef __META_SURFACE_ACTOR_X11_H__
|
||||
#define __META_SURFACE_ACTOR_X11_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
|
||||
#include <meta/display.h>
|
||||
#include <meta/window.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_SURFACE_ACTOR_X11 (meta_surface_actor_x11_get_type ())
|
||||
#define META_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11))
|
||||
#define META_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class))
|
||||
#define META_IS_SURFACE_ACTOR_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR_X11))
|
||||
#define META_IS_SURFACE_ACTOR_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR_X11))
|
||||
#define META_SURFACE_ACTOR_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR_X11, MetaSurfaceActorX11Class))
|
||||
|
||||
typedef struct _MetaSurfaceActorX11 MetaSurfaceActorX11;
|
||||
typedef struct _MetaSurfaceActorX11Class MetaSurfaceActorX11Class;
|
||||
|
||||
struct _MetaSurfaceActorX11
|
||||
{
|
||||
MetaSurfaceActor parent;
|
||||
};
|
||||
|
||||
struct _MetaSurfaceActorX11Class
|
||||
{
|
||||
MetaSurfaceActorClass parent_class;
|
||||
};
|
||||
|
||||
GType meta_surface_actor_x11_get_type (void);
|
||||
|
||||
MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window);
|
||||
|
||||
void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
|
||||
int width, int height);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __META_SURFACE_ACTOR_X11_H__ */
|
338
src/compositor/meta-surface-actor.c
Normal file
338
src/compositor/meta-surface-actor.c
Normal file
@ -0,0 +1,338 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:meta-surface-actor
|
||||
* @title: MetaSurfaceActor
|
||||
* @short_description: An actor representing a surface in the scene graph
|
||||
*
|
||||
* A surface can be either a shaped texture, or a group of shaped texture,
|
||||
* used to draw the content of a window.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
#include "meta-cullable.h"
|
||||
#include "meta-shaped-texture-private.h"
|
||||
|
||||
struct _MetaSurfaceActorPrivate
|
||||
{
|
||||
MetaShapedTexture *texture;
|
||||
|
||||
cairo_region_t *input_region;
|
||||
|
||||
/* Freeze/thaw accounting */
|
||||
guint needs_damage_all : 1;
|
||||
guint frozen : 1;
|
||||
};
|
||||
|
||||
static void cullable_iface_init (MetaCullableInterface *iface);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
|
||||
|
||||
enum {
|
||||
REPAINT_SCHEDULED,
|
||||
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
|
||||
cairo_rectangle_int_t *unobscured_bounds)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_pick (ClutterActor *actor,
|
||||
const ClutterColor *color)
|
||||
{
|
||||
MetaSurfaceActor *self = META_SURFACE_ACTOR (actor);
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
|
||||
if (!clutter_actor_should_pick_paint (actor))
|
||||
return;
|
||||
|
||||
/* If there is no region then use the regular pick */
|
||||
if (priv->input_region == NULL)
|
||||
CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->pick (actor, color);
|
||||
else
|
||||
{
|
||||
int n_rects;
|
||||
float *rectangles;
|
||||
int i;
|
||||
CoglPipeline *pipeline;
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglColor cogl_color;
|
||||
|
||||
n_rects = cairo_region_num_rectangles (priv->input_region);
|
||||
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
int pos = i * 4;
|
||||
|
||||
cairo_region_get_rectangle (priv->input_region, i, &rect);
|
||||
|
||||
rectangles[pos + 0] = rect.x;
|
||||
rectangles[pos + 1] = rect.y;
|
||||
rectangles[pos + 2] = rect.x + rect.width;
|
||||
rectangles[pos + 3] = rect.y + rect.height;
|
||||
}
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
|
||||
|
||||
pipeline = cogl_pipeline_new (ctx);
|
||||
cogl_pipeline_set_color (pipeline, &cogl_color);
|
||||
cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
|
||||
cogl_object_unref (pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_dispose (GObject *object)
|
||||
{
|
||||
MetaSurfaceActor *self = META_SURFACE_ACTOR (object);
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
|
||||
g_clear_pointer (&priv->input_region, cairo_region_destroy);
|
||||
|
||||
G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_surface_actor_dispose;
|
||||
actor_class->pick = meta_surface_actor_pick;
|
||||
|
||||
signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_cull_out (MetaCullable *cullable,
|
||||
cairo_region_t *unobscured_region,
|
||||
cairo_region_t *clip_region)
|
||||
{
|
||||
meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_reset_culling (MetaCullable *cullable)
|
||||
{
|
||||
meta_cullable_reset_culling_children (cullable);
|
||||
}
|
||||
|
||||
static void
|
||||
cullable_iface_init (MetaCullableInterface *iface)
|
||||
{
|
||||
iface->cull_out = meta_surface_actor_cull_out;
|
||||
iface->reset_culling = meta_surface_actor_reset_culling;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_surface_actor_init (MetaSurfaceActor *self)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv;
|
||||
|
||||
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
META_TYPE_SURFACE_ACTOR,
|
||||
MetaSurfaceActorPrivate);
|
||||
|
||||
priv->texture = META_SHAPED_TEXTURE (meta_shaped_texture_new ());
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->texture));
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
meta_surface_actor_get_image (MetaSurfaceActor *self,
|
||||
cairo_rectangle_int_t *clip)
|
||||
{
|
||||
return meta_shaped_texture_get_image (self->priv->texture, clip);
|
||||
}
|
||||
|
||||
MetaShapedTexture *
|
||||
meta_surface_actor_get_texture (MetaSurfaceActor *self)
|
||||
{
|
||||
return self->priv->texture;
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_update_area (MetaSurfaceActor *self,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
|
||||
if (meta_shaped_texture_update_area (priv->texture, x, y, width, height))
|
||||
g_signal_emit (self, signals[REPAINT_SCHEDULED], 0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_is_obscured (MetaSurfaceActor *self)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
return meta_shaped_texture_is_obscured (priv->texture);
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_set_input_region (MetaSurfaceActor *self,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
|
||||
if (priv->input_region)
|
||||
cairo_region_destroy (priv->input_region);
|
||||
|
||||
if (region)
|
||||
priv->input_region = cairo_region_reference (region);
|
||||
else
|
||||
priv->input_region = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
meta_shaped_texture_set_opaque_region (priv->texture, region);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_frozen (MetaSurfaceActor *self)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
return priv->frozen;
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_process_damage (MetaSurfaceActor *self,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
|
||||
if (is_frozen (self))
|
||||
{
|
||||
/* The window is frozen due to an effect in progress: we ignore damage
|
||||
* here on the off chance that this will stop the corresponding
|
||||
* texture_from_pixmap from being update.
|
||||
*
|
||||
* needs_damage_all tracks that some unknown damage happened while the
|
||||
* window was frozen so that when the window becomes unfrozen we can
|
||||
* issue a full window update to cover any lost damage.
|
||||
*
|
||||
* It should be noted that this is an unreliable mechanism since it's
|
||||
* quite likely that drivers will aim to provide a zero-copy
|
||||
* implementation of the texture_from_pixmap extension and in those cases
|
||||
* any drawing done to the window is always immediately reflected in the
|
||||
* texture regardless of damage event handling.
|
||||
*/
|
||||
priv->needs_damage_all = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_pre_paint (MetaSurfaceActor *self)
|
||||
{
|
||||
META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
|
||||
{
|
||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (self);
|
||||
CoglTexture *texture = meta_shaped_texture_get_texture (stex);
|
||||
|
||||
/* If we don't have a texture, like during initialization, assume
|
||||
* that we're ARGB32. */
|
||||
if (!texture)
|
||||
return TRUE;
|
||||
|
||||
switch (cogl_texture_get_components (texture))
|
||||
{
|
||||
case COGL_TEXTURE_COMPONENTS_A:
|
||||
case COGL_TEXTURE_COMPONENTS_RGBA:
|
||||
return TRUE;
|
||||
case COGL_TEXTURE_COMPONENTS_RG:
|
||||
case COGL_TEXTURE_COMPONENTS_RGB:
|
||||
case COGL_TEXTURE_COMPONENTS_DEPTH:
|
||||
return FALSE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_is_visible (MetaSurfaceActor *self)
|
||||
{
|
||||
return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self);
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_set_frozen (MetaSurfaceActor *self,
|
||||
gboolean frozen)
|
||||
{
|
||||
MetaSurfaceActorPrivate *priv = self->priv;
|
||||
|
||||
priv->frozen = frozen;
|
||||
|
||||
if (!frozen && priv->needs_damage_all)
|
||||
{
|
||||
/* Since we ignore damage events while a window is frozen for certain effects
|
||||
* we may need to issue an update_area() covering the whole pixmap if we
|
||||
* don't know what real damage has happened. */
|
||||
|
||||
meta_surface_actor_process_damage (self, 0, 0,
|
||||
clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)),
|
||||
clutter_actor_get_height (CLUTTER_ACTOR (priv->texture)));
|
||||
priv->needs_damage_all = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_should_unredirect (MetaSurfaceActor *self)
|
||||
{
|
||||
return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self);
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_set_unredirected (MetaSurfaceActor *self,
|
||||
gboolean unredirected)
|
||||
{
|
||||
META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_surface_actor_is_unredirected (MetaSurfaceActor *self)
|
||||
{
|
||||
return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self);
|
||||
}
|
||||
|
||||
MetaWindow *
|
||||
meta_surface_actor_get_window (MetaSurfaceActor *self)
|
||||
{
|
||||
return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self);
|
||||
}
|
85
src/compositor/meta-surface-actor.h
Normal file
85
src/compositor/meta-surface-actor.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#ifndef META_SURFACE_ACTOR_PRIVATE_H
|
||||
#define META_SURFACE_ACTOR_PRIVATE_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <meta/meta-shaped-texture.h>
|
||||
#include <meta/window.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_SURFACE_ACTOR (meta_surface_actor_get_type())
|
||||
#define META_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActor))
|
||||
#define META_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass))
|
||||
#define META_IS_SURFACE_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_SURFACE_ACTOR))
|
||||
#define META_IS_SURFACE_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_SURFACE_ACTOR))
|
||||
#define META_SURFACE_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_SURFACE_ACTOR, MetaSurfaceActorClass))
|
||||
|
||||
typedef struct _MetaSurfaceActor MetaSurfaceActor;
|
||||
typedef struct _MetaSurfaceActorClass MetaSurfaceActorClass;
|
||||
typedef struct _MetaSurfaceActorPrivate MetaSurfaceActorPrivate;
|
||||
|
||||
struct _MetaSurfaceActorClass
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActorClass parent_class;
|
||||
|
||||
void (* process_damage) (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height);
|
||||
void (* pre_paint) (MetaSurfaceActor *actor);
|
||||
gboolean (* is_visible) (MetaSurfaceActor *actor);
|
||||
|
||||
gboolean (* should_unredirect) (MetaSurfaceActor *actor);
|
||||
void (* set_unredirected) (MetaSurfaceActor *actor,
|
||||
gboolean unredirected);
|
||||
gboolean (* is_unredirected) (MetaSurfaceActor *actor);
|
||||
|
||||
MetaWindow *(* get_window) (MetaSurfaceActor *actor);
|
||||
};
|
||||
|
||||
struct _MetaSurfaceActor
|
||||
{
|
||||
ClutterActor parent;
|
||||
|
||||
MetaSurfaceActorPrivate *priv;
|
||||
};
|
||||
|
||||
GType meta_surface_actor_get_type (void);
|
||||
|
||||
cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self,
|
||||
cairo_rectangle_int_t *clip);
|
||||
|
||||
MetaShapedTexture *meta_surface_actor_get_texture (MetaSurfaceActor *self);
|
||||
MetaWindow *meta_surface_actor_get_window (MetaSurfaceActor *self);
|
||||
|
||||
gboolean meta_surface_actor_is_obscured (MetaSurfaceActor *self);
|
||||
gboolean meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
|
||||
cairo_rectangle_int_t *unobscured_bounds);
|
||||
|
||||
void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
|
||||
cairo_region_t *region);
|
||||
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
|
||||
cairo_region_t *region);
|
||||
|
||||
void meta_surface_actor_update_area (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height);
|
||||
|
||||
void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
|
||||
int x, int y, int width, int height);
|
||||
void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);
|
||||
gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor);
|
||||
gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor);
|
||||
|
||||
void meta_surface_actor_set_frozen (MetaSurfaceActor *actor,
|
||||
gboolean frozen);
|
||||
|
||||
gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor);
|
||||
void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor,
|
||||
gboolean unredirected);
|
||||
gboolean meta_surface_actor_is_unredirected (MetaSurfaceActor *actor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_SURFACE_ACTOR_PRIVATE_H */
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <meta/compositor-mutter.h>
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
MetaWindowActor *meta_window_actor_new (MetaWindow *window);
|
||||
|
||||
@ -24,8 +25,8 @@ void meta_window_actor_unmaximize (MetaWindowActor *self,
|
||||
MetaRectangle *old_rect,
|
||||
MetaRectangle *new_rect);
|
||||
|
||||
void meta_window_actor_process_damage (MetaWindowActor *self,
|
||||
XDamageNotifyEvent *event);
|
||||
void meta_window_actor_process_x11_damage (MetaWindowActor *self,
|
||||
XDamageNotifyEvent *event);
|
||||
|
||||
void meta_window_actor_pre_paint (MetaWindowActor *self);
|
||||
void meta_window_actor_post_paint (MetaWindowActor *self);
|
||||
@ -58,4 +59,7 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
void meta_window_actor_effect_completed (MetaWindowActor *actor,
|
||||
gulong event);
|
||||
|
||||
MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
|
||||
void meta_window_actor_update_surface (MetaWindowActor *self);
|
||||
|
||||
#endif /* META_WINDOW_ACTOR_PRIVATE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -122,7 +122,6 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
|
||||
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
|
||||
ClutterActor *stage = clutter_actor_get_stage (actor);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
|
||||
|
||||
/* Normally we expect an actor to be drawn at it's position on the screen.
|
||||
* However, if we're inside the paint of a ClutterClone, that won't be the
|
||||
@ -165,15 +164,6 @@ meta_window_group_paint (ClutterActor *actor)
|
||||
paint_y_offset = paint_y_origin - actor_y_origin;
|
||||
cairo_region_translate (clip_region, -paint_x_offset, -paint_y_offset);
|
||||
|
||||
if (info->unredirected_window != NULL)
|
||||
{
|
||||
cairo_rectangle_int_t unredirected_rect;
|
||||
|
||||
meta_window_get_frame_rect (info->unredirected_window, (MetaRectangle *)&unredirected_rect);
|
||||
cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
|
||||
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
|
||||
}
|
||||
|
||||
meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region);
|
||||
|
||||
cairo_region_destroy (unobscured_region);
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <gmodule.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DESTROY_TIMEOUT 250
|
||||
#define DESTROY_TIMEOUT 100
|
||||
#define MINIMIZE_TIMEOUT 250
|
||||
#define MAXIMIZE_TIMEOUT 250
|
||||
#define MAP_TIMEOUT 250
|
||||
@ -488,8 +488,6 @@ on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
|
||||
/* FIXME - we shouldn't assume the original scale, it should be saved
|
||||
* at the start of the effect */
|
||||
clutter_actor_set_scale (data->actor, 1.0, 1.0);
|
||||
clutter_actor_move_anchor_point_from_gravity (data->actor,
|
||||
CLUTTER_GRAVITY_NORTH_WEST);
|
||||
|
||||
/* Now notify the manager that we are done with this effect */
|
||||
meta_plugin_minimize_completed (plugin, window_actor);
|
||||
@ -526,9 +524,6 @@ minimize (MetaPlugin *plugin, MetaWindowActor *window_actor)
|
||||
|
||||
apriv->is_minimized = TRUE;
|
||||
|
||||
clutter_actor_move_anchor_point_from_gravity (actor,
|
||||
CLUTTER_GRAVITY_CENTER);
|
||||
|
||||
animation = clutter_actor_animate (actor,
|
||||
CLUTTER_EASE_IN_SINE,
|
||||
MINIMIZE_TIMEOUT,
|
||||
@ -567,8 +562,6 @@ on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data
|
||||
|
||||
/* FIXME - don't assume the original scale was 1.0 */
|
||||
clutter_actor_set_scale (data->actor, 1.0, 1.0);
|
||||
clutter_actor_move_anchor_point_from_gravity (data->actor,
|
||||
CLUTTER_GRAVITY_NORTH_WEST);
|
||||
|
||||
/* Now notify the manager that we are done with this effect */
|
||||
meta_plugin_maximize_completed (plugin, window_actor);
|
||||
@ -593,10 +586,8 @@ maximize (MetaPlugin *plugin,
|
||||
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;
|
||||
gfloat anchor_x = 0;
|
||||
gfloat anchor_y = 0;
|
||||
gdouble scale_x = 1.0;
|
||||
gdouble scale_y = 1.0;
|
||||
|
||||
type = meta_window_get_window_type (meta_window);
|
||||
|
||||
@ -620,13 +611,6 @@ maximize (MetaPlugin *plugin,
|
||||
scale_x = (gdouble)end_width / (gdouble) width;
|
||||
scale_y = (gdouble)end_height / (gdouble) height;
|
||||
|
||||
anchor_x = (gdouble)(x - end_x)*(gdouble)width /
|
||||
((gdouble)(end_width - width));
|
||||
anchor_y = (gdouble)(y - end_y)*(gdouble)height /
|
||||
((gdouble)(end_height - height));
|
||||
|
||||
clutter_actor_move_anchor_point (actor, anchor_x, anchor_y);
|
||||
|
||||
animation = clutter_actor_animate (actor,
|
||||
CLUTTER_EASE_IN_SINE,
|
||||
MAXIMIZE_TIMEOUT,
|
||||
@ -681,9 +665,6 @@ on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data)
|
||||
|
||||
apriv->tml_map = NULL;
|
||||
|
||||
clutter_actor_move_anchor_point_from_gravity (data->actor,
|
||||
CLUTTER_GRAVITY_NORTH_WEST);
|
||||
|
||||
/* Now notify the manager that we are done with this effect */
|
||||
meta_plugin_map_completed (plugin, window_actor);
|
||||
|
||||
@ -769,14 +750,12 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
|
||||
EffectCompleteData *data = g_new0 (EffectCompleteData, 1);
|
||||
ActorPrivate *apriv = get_actor_private (window_actor);
|
||||
|
||||
clutter_actor_move_anchor_point_from_gravity (actor,
|
||||
CLUTTER_GRAVITY_CENTER);
|
||||
|
||||
animation = clutter_actor_animate (actor,
|
||||
CLUTTER_EASE_IN_SINE,
|
||||
CLUTTER_EASE_OUT_QUAD,
|
||||
DESTROY_TIMEOUT,
|
||||
"scale-x", 0.0,
|
||||
"scale-y", 1.0,
|
||||
"opacity", 0,
|
||||
"scale-x", 0.8,
|
||||
"scale-y", 0.8,
|
||||
NULL);
|
||||
apriv->tml_destroy = clutter_animation_get_timeline (animation);
|
||||
data->plugin = plugin;
|
||||
|
@ -1,241 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/* Find the keycode for the key above the tab key */
|
||||
/*
|
||||
* Copyright 2010 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/>.
|
||||
*/
|
||||
|
||||
/* The standard cycle-windows keybinding should be the key above the
|
||||
* tab key. This will have a different keysym on different keyboards -
|
||||
* it's the ` (grave) key on US keyboards but something else on many
|
||||
* other national layouts. So we need to figure out the keycode for
|
||||
* this key without reference to key symbol.
|
||||
*
|
||||
* The "correct" way to do this is to get the XKB geometry from the
|
||||
* X server, find the Tab key, find the key above the Tab key in the
|
||||
* same section and use the keycode for that key. This is what I
|
||||
* implemented here, but unfortunately, fetching the geometry is rather
|
||||
* slow (It could take 20ms or more.)
|
||||
*
|
||||
* If you looking for a way to optimize Mutter startup performance:
|
||||
* On all Linux systems using evdev the key above TAB will have
|
||||
* keycode 49. (KEY_GRAVE=41 + the 8 code point offset between
|
||||
* evdev keysyms and X keysyms.) So a configure option
|
||||
* --with-above-tab-keycode=49 could be added that bypassed this
|
||||
* code. It wouldn't work right for displaying Mutter remotely
|
||||
* to a non-Linux X server, but that is pretty rare.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "display-private.h"
|
||||
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#ifdef HAVE_XKB
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/XKBgeom.h>
|
||||
|
||||
static guint
|
||||
compute_above_tab_keycode (Display *xdisplay)
|
||||
{
|
||||
XkbDescPtr keyboard;
|
||||
XkbGeometryPtr geometry;
|
||||
int i, j, k;
|
||||
int tab_keycode;
|
||||
char *tab_name;
|
||||
XkbSectionPtr tab_section;
|
||||
XkbBoundsRec tab_bounds;
|
||||
XkbKeyPtr best_key = NULL;
|
||||
guint best_keycode = (guint)-1;
|
||||
int best_x_dist = G_MAXINT;
|
||||
int best_y_dist = G_MAXINT;
|
||||
|
||||
/* We need only the Names and the Geometry, but asking for these results
|
||||
* in the Keyboard information retrieval failing for unknown reasons.
|
||||
* (Testing with xorg-1.9.1.) So we ask for a part that we don't need
|
||||
* as well.
|
||||
*/
|
||||
keyboard = XkbGetKeyboard (xdisplay,
|
||||
XkbGBN_ClientSymbolsMask | XkbGBN_KeyNamesMask | XkbGBN_GeometryMask,
|
||||
XkbUseCoreKbd);
|
||||
if (!keyboard)
|
||||
return best_keycode;
|
||||
|
||||
geometry = keyboard->geom;
|
||||
|
||||
/* There could potentially be multiple keys with the Tab keysym on the keyboard;
|
||||
* but XKeysymToKeycode() returns us the one that the alt-Tab binding will
|
||||
* use which is good enough
|
||||
*/
|
||||
tab_keycode = XKeysymToKeycode (xdisplay, XK_Tab);
|
||||
if (tab_keycode == 0 || tab_keycode < keyboard->min_key_code || tab_keycode > keyboard->max_key_code)
|
||||
goto out;
|
||||
|
||||
/* The keyboard geometry is stored by key "name" rather than keycode.
|
||||
* (Key names are 4-character strings like like TAB or AE01.) We use the
|
||||
* 'names' part of the keyboard description to map keycode to key name.
|
||||
*
|
||||
* XKB has a "key aliases" feature where a single keyboard key can have
|
||||
* multiple names (with separate sets of aliases in the 'names' part and
|
||||
* in the 'geometry' part), but I don't really understand it or how it is used,
|
||||
* so I'm ignoring it here.
|
||||
*/
|
||||
|
||||
tab_name = keyboard->names->keys[tab_keycode].name; /* Not NULL terminated! */
|
||||
|
||||
/* First, iterate through the keyboard geometry to find the tab key; the keyboard
|
||||
* geometry has a three-level heirarchy of section > row > key
|
||||
*/
|
||||
for (i = 0; i < geometry->num_sections; i++)
|
||||
{
|
||||
XkbSectionPtr section = &geometry->sections[i];
|
||||
for (j = 0; j < section->num_rows; j++)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
XkbRowPtr row = §ion->rows[j];
|
||||
for (k = 0; k < row->num_keys; k++)
|
||||
{
|
||||
XkbKeyPtr key = &row->keys[k];
|
||||
XkbShapePtr shape = XkbKeyShape (geometry, key);
|
||||
|
||||
if (row->vertical)
|
||||
y += key->gap;
|
||||
else
|
||||
x += key->gap;
|
||||
|
||||
if (strncmp (key->name.name, tab_name, XkbKeyNameLength) == 0)
|
||||
{
|
||||
tab_section = section;
|
||||
tab_bounds = shape->bounds;
|
||||
tab_bounds.x1 += row->left + x;
|
||||
tab_bounds.x2 += row->left + x;
|
||||
tab_bounds.y1 += row->top + y;
|
||||
tab_bounds.y2 += row->top + y;
|
||||
|
||||
goto found_tab;
|
||||
}
|
||||
|
||||
if (row->vertical)
|
||||
y += (shape->bounds.y2 - shape->bounds.y1);
|
||||
else
|
||||
x += (shape->bounds.x2 - shape->bounds.x1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No tab key found */
|
||||
goto out;
|
||||
|
||||
found_tab:
|
||||
|
||||
/* Now find the key that:
|
||||
* - Is in the same section as the Tab key
|
||||
* - Has a horizontal center in the Tab key's horizonal bounds
|
||||
* - Is above the Tab key at a distance closer than any other key
|
||||
* - In case of ties, has its horizontal center as close as possible
|
||||
* to the Tab key's horizontal center
|
||||
*/
|
||||
for (j = 0; j < tab_section->num_rows; j++)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
XkbRowPtr row = &tab_section->rows[j];
|
||||
for (k = 0; k < row->num_keys; k++)
|
||||
{
|
||||
XkbKeyPtr key = &row->keys[k];
|
||||
XkbShapePtr shape = XkbKeyShape(geometry, key);
|
||||
XkbBoundsRec bounds = shape->bounds;
|
||||
int x_center;
|
||||
int x_dist, y_dist;
|
||||
|
||||
if (row->vertical)
|
||||
y += key->gap;
|
||||
else
|
||||
x += key->gap;
|
||||
|
||||
bounds.x1 += row->left + x;
|
||||
bounds.x2 += row->left + x;
|
||||
bounds.y1 += row->top + y;
|
||||
bounds.y2 += row->top + y;
|
||||
|
||||
y_dist = tab_bounds.y1 - bounds.y2;
|
||||
if (y_dist < 0)
|
||||
continue;
|
||||
|
||||
x_center = (bounds.x1 + bounds.x2) / 2;
|
||||
if (x_center < tab_bounds.x1 || x_center > tab_bounds.x2)
|
||||
continue;
|
||||
|
||||
x_dist = ABS (x_center - (tab_bounds.x1 + tab_bounds.x2) / 2);
|
||||
|
||||
if (y_dist < best_y_dist ||
|
||||
(y_dist == best_y_dist && x_dist < best_x_dist))
|
||||
{
|
||||
best_key = key;
|
||||
best_x_dist = x_dist;
|
||||
best_y_dist = y_dist;
|
||||
}
|
||||
|
||||
if (row->vertical)
|
||||
y += (shape->bounds.y2 - shape->bounds.y1);
|
||||
else
|
||||
x += (shape->bounds.x2 - shape->bounds.x1);
|
||||
}
|
||||
}
|
||||
|
||||
if (best_key == NULL)
|
||||
goto out;
|
||||
|
||||
/* Now we need to resolve the name of the best key back to a keycode */
|
||||
for (i = keyboard->min_key_code; i < keyboard->max_key_code; i++)
|
||||
{
|
||||
if (strncmp (best_key->name.name, keyboard->names->keys[i].name, XkbKeyNameLength) == 0)
|
||||
{
|
||||
best_keycode = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
XkbFreeKeyboard (keyboard, 0, True);
|
||||
|
||||
return best_keycode;
|
||||
}
|
||||
#else /* !HAVE_XKB */
|
||||
static guint
|
||||
compute_above_tab_keycode (Display *xdisplay)
|
||||
{
|
||||
return XKeysymToKeycode (xdisplay, XK_grave);
|
||||
}
|
||||
#endif /* HAVE_XKB */
|
||||
|
||||
guint
|
||||
meta_display_get_above_tab_keycode (MetaDisplay *display)
|
||||
{
|
||||
if (display->above_tab_keycode == 0) /* not yet computed */
|
||||
display->above_tab_keycode = compute_above_tab_keycode (display->xdisplay);
|
||||
|
||||
if (display->above_tab_keycode == (guint)-1) /* failed to compute */
|
||||
return 0;
|
||||
else
|
||||
return display->above_tab_keycode;
|
||||
}
|
@ -366,11 +366,25 @@ meta_barrier_fire_event (MetaBarrier *barrier,
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_display_process_barrier_event (MetaDisplay *display,
|
||||
XIBarrierEvent *xev)
|
||||
meta_display_process_barrier_event (MetaDisplay *display,
|
||||
XIEvent *event)
|
||||
{
|
||||
MetaBarrier *barrier;
|
||||
XIBarrierEvent *xev;
|
||||
|
||||
if (event == NULL)
|
||||
return FALSE;
|
||||
|
||||
switch (event->evtype)
|
||||
{
|
||||
case XI_BarrierHit:
|
||||
case XI_BarrierLeave:
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xev = (XIBarrierEvent *) event;
|
||||
barrier = g_hash_table_lookup (display->xids, &xev->barrier);
|
||||
if (barrier != NULL)
|
||||
{
|
||||
|
110
src/core/bell.c
110
src/core/bell.c
@ -58,88 +58,6 @@
|
||||
#include <canberra-gtk.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* bell_flash_screen:
|
||||
* @display: The display which owns the screen (rather redundant)
|
||||
* @screen: The screen to flash
|
||||
*
|
||||
* Flashes one entire screen. This is done by making a window the size of the
|
||||
* whole screen (or reusing the old one, if it's still around), mapping it,
|
||||
* painting it white and then black, and then unmapping it. We set saveunder so
|
||||
* that all the windows behind it come back immediately.
|
||||
*
|
||||
* Unlike frame flashes, we don't do fullscreen flashes with a timeout; rather,
|
||||
* we do them in one go, because we don't have to rely on the theme code
|
||||
* redrawing the frame for us in order to do the flash.
|
||||
*/
|
||||
/*
|
||||
* Bug: The way I read it, this appears not to do the flash
|
||||
* the first time we flash a particular display. Am I wrong?
|
||||
*
|
||||
* Bug: This appears to destroy our current XSync status.
|
||||
*/
|
||||
static void
|
||||
bell_flash_screen (MetaDisplay *display,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
Window root = screen->xroot;
|
||||
int width = screen->rect.width;
|
||||
int height = screen->rect.height;
|
||||
|
||||
if (screen->flash_window == None)
|
||||
{
|
||||
Visual *visual = (Visual *)CopyFromParent;
|
||||
XSetWindowAttributes xswa;
|
||||
int depth = CopyFromParent;
|
||||
xswa.save_under = True;
|
||||
xswa.override_redirect = True;
|
||||
/*
|
||||
* TODO: use XGetVisualInfo and determine which is an
|
||||
* overlay, if one is present, and use the Overlay visual
|
||||
* for this window (for performance reasons).
|
||||
* Not sure how to tell this yet...
|
||||
*/
|
||||
screen->flash_window = XCreateWindow (display->xdisplay, root,
|
||||
0, 0, width, height,
|
||||
0, depth,
|
||||
InputOutput,
|
||||
visual,
|
||||
/* note: XSun doesn't like SaveUnder here */
|
||||
CWSaveUnder | CWOverrideRedirect,
|
||||
&xswa);
|
||||
XSelectInput (display->xdisplay, screen->flash_window, ExposureMask);
|
||||
XMapWindow (display->xdisplay, screen->flash_window);
|
||||
XSync (display->xdisplay, False);
|
||||
XFlush (display->xdisplay);
|
||||
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just draw something in the window */
|
||||
GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL);
|
||||
XMapWindow (display->xdisplay, screen->flash_window);
|
||||
XSetForeground (display->xdisplay, gc,
|
||||
WhitePixel (display->xdisplay,
|
||||
XScreenNumberOfScreen (screen->xscreen)));
|
||||
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||
0, 0, width, height);
|
||||
XSetForeground (display->xdisplay, gc,
|
||||
BlackPixel (display->xdisplay,
|
||||
XScreenNumberOfScreen (screen->xscreen)));
|
||||
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||
0, 0, width, height);
|
||||
XFlush (display->xdisplay);
|
||||
XSync (display->xdisplay, False);
|
||||
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||
XFreeGC (display->xdisplay, gc);
|
||||
}
|
||||
|
||||
if (meta_prefs_get_focus_mode () != G_DESKTOP_FOCUS_MODE_CLICK &&
|
||||
!display->mouse_mode)
|
||||
meta_display_increment_focus_sentinel (display);
|
||||
XFlush (display->xdisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
* bell_flash_fullscreen:
|
||||
* @display: The display the event came in on
|
||||
@ -156,34 +74,8 @@ static void
|
||||
bell_flash_fullscreen (MetaDisplay *display,
|
||||
XkbAnyEvent *xkb_ev)
|
||||
{
|
||||
XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
|
||||
MetaScreen *screen;
|
||||
|
||||
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||
if (xkb_bell_ev->window != None)
|
||||
{
|
||||
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
|
||||
if (screen)
|
||||
{
|
||||
if (display->compositor)
|
||||
meta_compositor_flash_screen (display->compositor, screen);
|
||||
else
|
||||
bell_flash_screen (display, screen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GSList *screen_list = display->screens;
|
||||
while (screen_list)
|
||||
{
|
||||
screen = (MetaScreen *) screen_list->data;
|
||||
if (display->compositor)
|
||||
meta_compositor_flash_screen (display->compositor, screen);
|
||||
else
|
||||
bell_flash_screen (display, screen);
|
||||
screen_list = screen_list->next;
|
||||
}
|
||||
}
|
||||
meta_compositor_flash_screen (display->compositor, display->screen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,6 +425,7 @@ setup_constraint_info (ConstraintInfo *info,
|
||||
* the monitor.
|
||||
*/
|
||||
if (meta_prefs_get_force_fullscreen() &&
|
||||
window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
|
||||
!window->hide_titlebar_when_maximized &&
|
||||
(window->decorated || !meta_window_is_client_decorated (window)) &&
|
||||
meta_rectangle_equal (new, &monitor_info->rect) &&
|
||||
|
@ -27,15 +27,6 @@
|
||||
#include "window-private.h"
|
||||
#include "frame.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_IS_CONFIGURE_REQUEST = 1 << 0,
|
||||
META_DO_GRAVITY_ADJUST = 1 << 1,
|
||||
META_IS_USER_ACTION = 1 << 2,
|
||||
META_IS_MOVE_ACTION = 1 << 3,
|
||||
META_IS_RESIZE_ACTION = 1 << 4
|
||||
} MetaMoveResizeFlags;
|
||||
|
||||
void meta_window_constrain (MetaWindow *window,
|
||||
MetaMoveResizeFlags flags,
|
||||
int resize_gravity,
|
||||
|
@ -153,7 +153,7 @@ meta_core_get (Display *xdisplay,
|
||||
break;
|
||||
|
||||
default:
|
||||
meta_warning(_("Unknown window information request: %d"), request);
|
||||
meta_warning("Unknown window information request: %d\n", request);
|
||||
}
|
||||
|
||||
request = va_arg (args, MetaCoreGetType);
|
||||
@ -270,9 +270,11 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
|
||||
MetaDisplay *display;
|
||||
MetaScreen *screen;
|
||||
MetaWindow *grab_window;
|
||||
MetaStackWindow stack_window;
|
||||
MetaStackWindow stack_sibling;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_xwindow (display, xwindow);
|
||||
screen = display->screen;
|
||||
grab_window = display->grab_window;
|
||||
|
||||
if (grab_window == NULL)
|
||||
@ -281,9 +283,13 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
|
||||
changes.stack_mode = Below;
|
||||
changes.sibling = meta_window_get_toplevel_xwindow (grab_window);
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = xwindow;
|
||||
stack_sibling.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_sibling.x11.xwindow = changes.sibling;
|
||||
meta_stack_tracker_record_lower_below (screen->stack_tracker,
|
||||
xwindow,
|
||||
changes.sibling,
|
||||
&stack_window,
|
||||
&stack_sibling,
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
|
||||
meta_error_trap_push (display);
|
||||
@ -597,13 +603,10 @@ meta_core_get_workspace_name_with_index (Display *xdisplay,
|
||||
int index)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaScreen *screen;
|
||||
MetaWorkspace *workspace;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_root (display, xroot);
|
||||
g_assert (screen != NULL);
|
||||
workspace = meta_screen_get_workspace_by_index (screen, index);
|
||||
workspace = meta_screen_get_workspace_by_index (display->screen, index);
|
||||
return workspace ? meta_workspace_get_name (workspace) : NULL;
|
||||
}
|
||||
|
||||
@ -624,7 +627,7 @@ meta_core_begin_grab_op (Display *xdisplay,
|
||||
MetaScreen *screen;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
screen = meta_display_screen_for_xwindow (display, frame_xwindow);
|
||||
screen = display->screen;
|
||||
|
||||
g_assert (screen != NULL);
|
||||
|
||||
@ -664,10 +667,6 @@ meta_core_get_grab_frame (Display *xdisplay)
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
|
||||
g_assert (display != NULL);
|
||||
g_assert (display->grab_op == META_GRAB_OP_NONE ||
|
||||
display->grab_screen != NULL);
|
||||
g_assert (display->grab_op == META_GRAB_OP_NONE ||
|
||||
display->grab_screen->display->xdisplay == xdisplay);
|
||||
|
||||
if (display->grab_op != META_GRAB_OP_NONE &&
|
||||
display->grab_window &&
|
||||
@ -712,16 +711,6 @@ meta_core_set_screen_cursor (Display *xdisplay,
|
||||
meta_frame_set_screen_cursor (window->frame, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_increment_event_serial (Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
|
||||
meta_display_increment_event_serial (display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_invalidate_default_icons (void)
|
||||
{
|
||||
|
@ -193,12 +193,6 @@ void meta_core_set_screen_cursor (Display *xdisplay,
|
||||
Window frame_on_screen,
|
||||
MetaCursor cursor);
|
||||
|
||||
/* Used because we ignore EnterNotify when a window is unmapped that
|
||||
* really shouldn't cause focus changes, by comparing the event serial
|
||||
* of the EnterNotify and the UnmapNotify.
|
||||
*/
|
||||
void meta_core_increment_event_serial (Display *display);
|
||||
|
||||
void meta_invalidate_default_icons (void);
|
||||
|
||||
void meta_core_add_old_event_mask (Display *xdisplay,
|
||||
|
@ -37,18 +37,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
|
||||
static void meta_window_present_delete_dialog (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
|
||||
static void
|
||||
delete_ping_reply_func (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
delete_ping_reply_func (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
void *user_data)
|
||||
{
|
||||
meta_topic (META_DEBUG_PING,
|
||||
"Got reply to delete ping for %s\n",
|
||||
((MetaWindow*)user_data)->desc);
|
||||
meta_topic (META_DEBUG_PING, "Got reply to delete ping for %s\n", window->desc);
|
||||
|
||||
/* we do nothing */
|
||||
}
|
||||
@ -66,12 +65,10 @@ dialog_exited (GPid pid, int status, gpointer user_data)
|
||||
}
|
||||
|
||||
static void
|
||||
delete_ping_timeout_func (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
delete_ping_timeout_func (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
void *user_data)
|
||||
{
|
||||
MetaWindow *window = user_data;
|
||||
char *window_title;
|
||||
gchar *window_content, *tmp;
|
||||
GPid dialog_pid;
|
||||
@ -135,36 +132,18 @@ void
|
||||
meta_window_check_alive (MetaWindow *window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
meta_display_ping_window (window->display,
|
||||
window,
|
||||
meta_display_ping_window (window,
|
||||
timestamp,
|
||||
delete_ping_reply_func,
|
||||
delete_ping_timeout_func,
|
||||
window);
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_delete (MetaWindow *window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
meta_error_trap_push (window->display);
|
||||
if (window->delete_window)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Deleting %s with delete_window request\n",
|
||||
window->desc);
|
||||
meta_window_send_icccm_message (window,
|
||||
window->display->atom_WM_DELETE_WINDOW,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Deleting %s with explicit kill\n",
|
||||
window->desc);
|
||||
XKillClient (window->display->xdisplay, window->xwindow);
|
||||
}
|
||||
meta_error_trap_pop (window->display);
|
||||
META_WINDOW_GET_CLASS (window)->delete (window, timestamp);
|
||||
|
||||
meta_window_check_alive (window, timestamp);
|
||||
|
||||
@ -197,33 +176,10 @@ meta_window_delete (MetaWindow *window,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
meta_window_kill (MetaWindow *window)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Killing %s brutally\n",
|
||||
window->desc);
|
||||
|
||||
if (!meta_window_is_remote (window) &&
|
||||
window->net_wm_pid > 0)
|
||||
{
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Killing %s with kill()\n",
|
||||
window->desc);
|
||||
|
||||
if (kill (window->net_wm_pid, 9) < 0)
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Failed to signal %s: %s\n",
|
||||
window->desc, strerror (errno));
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_WINDOW_OPS,
|
||||
"Disconnecting %s with XKillClient()\n",
|
||||
window->desc);
|
||||
meta_error_trap_push (window->display);
|
||||
XKillClient (window->display->xdisplay, window->xwindow);
|
||||
meta_error_trap_pop (window->display);
|
||||
META_WINDOW_GET_CLASS (window)->kill (window);
|
||||
}
|
||||
|
||||
void
|
||||
@ -258,8 +214,7 @@ meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
|
||||
if (w->xtransient_for == window->xwindow &&
|
||||
w->res_class &&
|
||||
if (w->transient_for == window && w->res_class &&
|
||||
g_ascii_strcasecmp (w->res_class, "mutter-dialog") == 0)
|
||||
{
|
||||
meta_window_activate (w, timestamp);
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "keybindings-private.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/barrier.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
#include <libsn/sn.h>
|
||||
@ -54,10 +55,9 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
|
||||
|
||||
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
|
||||
|
||||
typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
guint32 timestamp,
|
||||
gpointer user_data);
|
||||
typedef void (* MetaWindowPingFunc) (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
gpointer user_data);
|
||||
|
||||
typedef enum {
|
||||
META_LIST_DEFAULT = 0, /* normal windows */
|
||||
@ -91,6 +91,8 @@ struct _MetaDisplay
|
||||
char *name;
|
||||
Display *xdisplay;
|
||||
|
||||
int clutter_event_filter;
|
||||
|
||||
Window leader_window;
|
||||
Window timestamp_pinging_window;
|
||||
|
||||
@ -143,17 +145,12 @@ struct _MetaDisplay
|
||||
* multiple events with the same serial.
|
||||
*/
|
||||
guint focused_by_us : 1;
|
||||
|
||||
guint static_gravity_works : 1;
|
||||
|
||||
/*< private-ish >*/
|
||||
guint error_trap_synced_at_last_pop : 1;
|
||||
GSList *screens;
|
||||
MetaScreen *active_screen;
|
||||
MetaScreen *screen;
|
||||
GHashTable *xids;
|
||||
int error_traps;
|
||||
int (* error_trap_handler) (Display *display,
|
||||
XErrorEvent *error);
|
||||
GHashTable *wayland_windows;
|
||||
|
||||
int server_grab_count;
|
||||
|
||||
/* serials of leave/unmap events that may
|
||||
@ -185,11 +182,10 @@ struct _MetaDisplay
|
||||
MetaWindow* autoraise_window;
|
||||
|
||||
/* Alt+click button grabs */
|
||||
unsigned int window_grab_modifiers;
|
||||
ClutterModifierType window_grab_modifiers;
|
||||
|
||||
/* current window operation */
|
||||
MetaGrabOp grab_op;
|
||||
MetaScreen *grab_screen;
|
||||
MetaWindow *grab_window;
|
||||
Window grab_xwindow;
|
||||
int grab_button;
|
||||
@ -200,7 +196,6 @@ struct _MetaDisplay
|
||||
int grab_tile_monitor_number;
|
||||
int grab_latest_motion_x;
|
||||
int grab_latest_motion_y;
|
||||
gulong grab_mask;
|
||||
guint grab_have_pointer : 1;
|
||||
guint grab_have_keyboard : 1;
|
||||
guint grab_frame_action : 1;
|
||||
@ -212,7 +207,6 @@ struct _MetaDisplay
|
||||
gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */
|
||||
MetaResizePopup *grab_resize_popup;
|
||||
GTimeVal grab_last_moveresize_time;
|
||||
guint32 grab_motion_notify_time;
|
||||
GList* grab_old_window_stacking;
|
||||
MetaEdgeResistanceData *grab_edge_resistance_data;
|
||||
unsigned int grab_last_user_action_was_snap;
|
||||
@ -236,11 +230,7 @@ struct _MetaDisplay
|
||||
int max_keycode;
|
||||
KeySym *keymap;
|
||||
int keysyms_per_keycode;
|
||||
XModifierKeymap *modmap;
|
||||
unsigned int above_tab_keycode;
|
||||
unsigned int ignored_modifier_mask;
|
||||
unsigned int num_lock_mask;
|
||||
unsigned int scroll_lock_mask;
|
||||
unsigned int hyper_mask;
|
||||
unsigned int super_mask;
|
||||
unsigned int meta_mask;
|
||||
@ -351,10 +341,6 @@ struct _MetaDisplayClass
|
||||
gboolean meta_display_open (void);
|
||||
void meta_display_close (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
MetaScreen* meta_display_screen_for_x_screen (MetaDisplay *display,
|
||||
Screen *screen);
|
||||
MetaScreen* meta_display_screen_for_xwindow (MetaDisplay *display,
|
||||
Window xindow);
|
||||
void meta_display_grab (MetaDisplay *display);
|
||||
void meta_display_ungrab (MetaDisplay *display);
|
||||
|
||||
@ -377,6 +363,11 @@ void meta_display_register_x_window (MetaDisplay *display,
|
||||
void meta_display_unregister_x_window (MetaDisplay *display,
|
||||
Window xwindow);
|
||||
|
||||
void meta_display_register_wayland_window (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
void meta_display_unregister_wayland_window (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display,
|
||||
XSyncAlarm alarm);
|
||||
@ -436,20 +427,22 @@ void meta_display_retheme_all (void);
|
||||
void meta_display_set_cursor_theme (const char *theme,
|
||||
int size);
|
||||
|
||||
void meta_display_ping_window (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
void meta_display_ping_window (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
MetaWindowPingFunc ping_reply_func,
|
||||
MetaWindowPingFunc ping_timeout_func,
|
||||
void *user_data);
|
||||
gboolean meta_display_window_has_pending_pings (MetaDisplay *display,
|
||||
MetaWindow *window);
|
||||
void meta_display_pong_for_serial (MetaDisplay *display,
|
||||
guint32 serial);
|
||||
|
||||
int meta_resize_gravity_from_grab_op (MetaGrabOp op);
|
||||
|
||||
gboolean meta_grab_op_is_moving (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_resizing (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_mouse (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_clicking (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_wayland (MetaGrabOp op);
|
||||
gboolean meta_grab_op_is_keyboard (MetaGrabOp op);
|
||||
|
||||
void meta_display_devirtualize_modifiers (MetaDisplay *display,
|
||||
MetaVirtualModifier modifiers,
|
||||
@ -464,18 +457,14 @@ void meta_display_queue_autoraise_callback (MetaDisplay *display,
|
||||
void meta_display_remove_autoraise_callback (MetaDisplay *display);
|
||||
|
||||
void meta_display_overlay_key_activate (MetaDisplay *display);
|
||||
void meta_display_accelerator_activate (MetaDisplay *display,
|
||||
guint action,
|
||||
guint deviceid,
|
||||
guint timestamp);
|
||||
void meta_display_accelerator_activate (MetaDisplay *display,
|
||||
guint action,
|
||||
ClutterKeyEvent *event);
|
||||
gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display);
|
||||
|
||||
/* In above-tab-keycode.c */
|
||||
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
|
||||
|
||||
#ifdef HAVE_XI23
|
||||
gboolean meta_display_process_barrier_event (MetaDisplay *display,
|
||||
XIBarrierEvent *event);
|
||||
gboolean meta_display_process_barrier_event (MetaDisplay *display,
|
||||
XIEvent *event);
|
||||
#endif /* HAVE_XI23 */
|
||||
|
||||
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
@ -483,4 +472,16 @@ void meta_display_set_input_focus_xwindow (MetaDisplay *display,
|
||||
Window window,
|
||||
guint32 timestamp);
|
||||
|
||||
void meta_display_sync_wayland_input_focus (MetaDisplay *display);
|
||||
void meta_display_update_focus_window (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
Window xwindow,
|
||||
gulong serial,
|
||||
gboolean focused_by_us);
|
||||
|
||||
void meta_display_sanity_check_timestamps (MetaDisplay *display,
|
||||
guint32 timestamp);
|
||||
gboolean meta_display_timestamp_too_old (MetaDisplay *display,
|
||||
guint32 *timestamp);
|
||||
|
||||
#endif
|
||||
|
3037
src/core/display.c
3037
src/core/display.c
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,6 @@
|
||||
*/
|
||||
#define WINDOW_EDGES_RELEVANT(window, display) \
|
||||
meta_window_should_be_showing (window) && \
|
||||
window->screen == display->grab_screen && \
|
||||
window != display->grab_window && \
|
||||
window->type != META_WINDOW_DESKTOP && \
|
||||
window->type != META_WINDOW_MENU && \
|
||||
@ -963,9 +962,9 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
|
||||
/*
|
||||
* 1st: Get the list of relevant windows, from bottom to top
|
||||
*/
|
||||
stacked_windows =
|
||||
meta_stack_list_windows (display->grab_screen->stack,
|
||||
display->grab_screen->active_workspace);
|
||||
stacked_windows =
|
||||
meta_stack_list_windows (display->screen->stack,
|
||||
display->screen->active_workspace);
|
||||
|
||||
/*
|
||||
* 2nd: we need to separate that stacked list into a list of windows that
|
||||
@ -1026,7 +1025,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
|
||||
* by other windows or DOCKS, but that's handled below).
|
||||
*/
|
||||
meta_rectangle_intersect (&cur_rect,
|
||||
&display->grab_screen->rect,
|
||||
&display->screen->rect,
|
||||
&reduced);
|
||||
|
||||
new_edges = NULL;
|
||||
@ -1123,8 +1122,8 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
|
||||
*/
|
||||
cache_edges (display,
|
||||
edges,
|
||||
display->grab_screen->active_workspace->monitor_edges,
|
||||
display->grab_screen->active_workspace->screen_edges);
|
||||
display->screen->active_workspace->monitor_edges,
|
||||
display->screen->active_workspace->screen_edges);
|
||||
g_list_free (edges);
|
||||
|
||||
/*
|
||||
|
@ -55,12 +55,6 @@ meta_error_trap_pop (MetaDisplay *display)
|
||||
gdk_error_trap_pop_ignored ();
|
||||
}
|
||||
|
||||
void
|
||||
meta_error_trap_push_with_return (MetaDisplay *display)
|
||||
{
|
||||
gdk_error_trap_push ();
|
||||
}
|
||||
|
||||
int
|
||||
meta_error_trap_pop_with_return (MetaDisplay *display)
|
||||
{
|
||||
|
2224
src/core/events.c
Normal file
2224
src/core/events.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,10 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
|
||||
* Copyright (C) 2003, 2004 Rob Adams
|
||||
* Copyright (C) 2004-2006 Elijah Newren
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@ -15,18 +18,15 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef META_CURSOR_TRACKER_PRIVATE_H
|
||||
#define META_CURSOR_TRACKER_PRIVATE_H
|
||||
#include <meta/display.h>
|
||||
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
#ifndef META_EVENTS_H
|
||||
#define META_EVENTS_H
|
||||
|
||||
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||
XEvent *xevent);
|
||||
void meta_display_init_events (MetaDisplay *display);
|
||||
void meta_display_free_events (MetaDisplay *display);
|
||||
|
||||
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||
MetaCursor cursor);
|
||||
#endif
|
||||
|
@ -35,8 +35,7 @@
|
||||
ButtonPressMask | ButtonReleaseMask | \
|
||||
PointerMotionMask | PointerMotionHintMask | \
|
||||
EnterWindowMask | LeaveWindowMask | \
|
||||
FocusChangeMask | \
|
||||
ColormapChangeMask)
|
||||
FocusChangeMask)
|
||||
|
||||
void
|
||||
meta_window_ensure_frame (MetaWindow *window)
|
||||
@ -45,6 +44,7 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
XSetWindowAttributes attrs;
|
||||
Visual *visual;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame)
|
||||
return;
|
||||
@ -100,8 +100,10 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
frame->rect.height,
|
||||
frame->window->screen->number,
|
||||
&create_serial);
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = frame->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
frame->xwindow,
|
||||
&stack_window,
|
||||
create_serial);
|
||||
|
||||
meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
|
||||
@ -125,8 +127,9 @@ meta_window_ensure_frame (MetaWindow *window)
|
||||
window->rect.x = 0;
|
||||
window->rect.y = 0;
|
||||
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_remove (window->screen->stack_tracker,
|
||||
window->xwindow,
|
||||
&stack_window,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
@ -161,6 +164,7 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
{
|
||||
MetaFrame *frame;
|
||||
MetaFrameBorders borders;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
if (window->frame == NULL)
|
||||
return;
|
||||
@ -187,8 +191,10 @@ meta_window_destroy_frame (MetaWindow *window)
|
||||
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
|
||||
window->unmaps_pending += 1;
|
||||
}
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = window->xwindow;
|
||||
meta_stack_tracker_record_add (window->screen->stack_tracker,
|
||||
window->xwindow,
|
||||
&stack_window,
|
||||
XNextRequest (window->display->xdisplay));
|
||||
XReparentWindow (window->display->xdisplay,
|
||||
window->xwindow,
|
||||
|
@ -104,9 +104,9 @@ gboolean meta_window_grab_all_keys (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
void meta_window_ungrab_all_keys (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
gboolean meta_display_process_key_event (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
XIDeviceEvent *event);
|
||||
gboolean meta_display_process_key_event (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
ClutterKeyEvent *event);
|
||||
void meta_display_process_mapping_event (MetaDisplay *display,
|
||||
XEvent *event);
|
||||
|
||||
@ -122,7 +122,3 @@ void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
|
||||
const char *meta_prefs_get_iso_next_group_option (void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
182
src/core/main.c
182
src/core/main.c
@ -50,12 +50,11 @@
|
||||
#include "display-private.h"
|
||||
#include <meta/errors.h>
|
||||
#include "ui.h"
|
||||
#include "session.h"
|
||||
#include <meta/prefs.h>
|
||||
#include <meta/compositor.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
@ -71,12 +70,16 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
|
||||
#ifdef HAVE_INTROSPECTION
|
||||
#include <girepository.h>
|
||||
#endif
|
||||
|
||||
#include "x11/session.h"
|
||||
|
||||
#include "wayland/meta-wayland.h"
|
||||
#include "backends/meta-backend.h"
|
||||
|
||||
/*
|
||||
* The exit code we'll return to our parent process when we eventually die.
|
||||
*/
|
||||
@ -187,6 +190,8 @@ static gchar *opt_client_id;
|
||||
static gboolean opt_replace_wm;
|
||||
static gboolean opt_disable_sm;
|
||||
static gboolean opt_sync;
|
||||
static gboolean opt_wayland;
|
||||
static gboolean opt_display_server;
|
||||
|
||||
static GOptionEntry meta_options[] = {
|
||||
{
|
||||
@ -224,6 +229,17 @@ static GOptionEntry meta_options[] = {
|
||||
N_("Make X calls synchronous"),
|
||||
NULL
|
||||
},
|
||||
{
|
||||
"wayland", 0, 0, G_OPTION_ARG_NONE,
|
||||
&opt_wayland,
|
||||
N_("Run as a wayland compositor"),
|
||||
NULL
|
||||
},
|
||||
{
|
||||
"display-server", 0, 0, G_OPTION_ARG_NONE,
|
||||
&opt_display_server,
|
||||
N_("Run as a full display server, rather than nested")
|
||||
},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@ -247,78 +263,9 @@ meta_get_option_context (void)
|
||||
|
||||
ctx = g_option_context_new (NULL);
|
||||
g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE);
|
||||
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
|
||||
g_option_context_add_group (ctx, cogl_get_option_group ());
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* the X fd, but we do have to deal with dispatching events that accumulate
|
||||
* in the clutter queue. This happens, for example, when clutter generate
|
||||
* enter/leave events on mouse motion - several events are queued in the
|
||||
* clutter queue but only one dispatched. It could also happen because of
|
||||
* explicit calls to clutter_event_put(). We add a very simple custom
|
||||
* event loop source which is simply responsible for pulling events off
|
||||
* of the queue and dispatching them before we block for new events.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
event_prepare (GSource *source,
|
||||
gint *timeout_)
|
||||
{
|
||||
*timeout_ = -1;
|
||||
|
||||
return clutter_events_pending ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_check (GSource *source)
|
||||
{
|
||||
return clutter_events_pending ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterEvent *event = clutter_event_get ();
|
||||
|
||||
if (event)
|
||||
{
|
||||
clutter_do_event (event);
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs event_funcs = {
|
||||
event_prepare,
|
||||
event_check,
|
||||
event_dispatch
|
||||
};
|
||||
|
||||
static void
|
||||
meta_clutter_init (void)
|
||||
{
|
||||
clutter_x11_set_display (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
|
||||
clutter_x11_disable_event_retrieval ();
|
||||
|
||||
if (CLUTTER_INIT_SUCCESS == clutter_init (NULL, NULL))
|
||||
{
|
||||
GSource *source = g_source_new (&event_funcs, sizeof (GSource));
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_fatal ("Unable to initialize Clutter.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_select_display:
|
||||
*
|
||||
@ -328,16 +275,17 @@ meta_clutter_init (void)
|
||||
* also is %NULL, use the default - :0.0
|
||||
*/
|
||||
static void
|
||||
meta_select_display (gchar *display_name)
|
||||
meta_select_display (char *display_arg)
|
||||
{
|
||||
gchar *envVar = "";
|
||||
const char *display_name;
|
||||
|
||||
if (display_arg)
|
||||
display_name = (const char *) display_arg;
|
||||
else
|
||||
display_name = g_getenv ("MUTTER_DISPLAY");
|
||||
|
||||
if (display_name)
|
||||
envVar = g_strconcat ("DISPLAY=", display_name, NULL);
|
||||
else if (g_getenv ("MUTTER_DISPLAY"))
|
||||
envVar = g_strconcat ("DISPLAY=",
|
||||
g_getenv ("MUTTER_DISPLAY"), NULL);
|
||||
/* DO NOT FREE envVar, putenv() sucks */
|
||||
putenv (envVar);
|
||||
g_setenv ("DISPLAY", display_name, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -348,28 +296,17 @@ meta_finalize (void)
|
||||
if (display)
|
||||
meta_display_close (display,
|
||||
CurrentTime); /* I doubt correct timestamps matter here */
|
||||
}
|
||||
|
||||
static int sigterm_pipe_fds[2] = { -1, -1 };
|
||||
|
||||
static void
|
||||
sigterm_handler (int signum)
|
||||
{
|
||||
if (sigterm_pipe_fds[1] >= 0)
|
||||
{
|
||||
int G_GNUC_UNUSED dummy;
|
||||
|
||||
dummy = write (sigterm_pipe_fds[1], "", 1);
|
||||
close (sigterm_pipe_fds[1]);
|
||||
sigterm_pipe_fds[1] = -1;
|
||||
}
|
||||
if (meta_is_wayland_compositor ())
|
||||
meta_wayland_finalize ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_sigterm (void)
|
||||
on_sigterm (gpointer user_data)
|
||||
{
|
||||
meta_quit (META_EXIT_SUCCESS);
|
||||
return FALSE;
|
||||
meta_quit (EXIT_SUCCESS);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -383,9 +320,8 @@ meta_init (void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigset_t empty_mask;
|
||||
GIOChannel *channel;
|
||||
ClutterSettings *clutter_settings;
|
||||
|
||||
|
||||
sigemptyset (&empty_mask);
|
||||
act.sa_handler = SIG_IGN;
|
||||
act.sa_mask = empty_mask;
|
||||
@ -399,26 +335,18 @@ meta_init (void)
|
||||
g_strerror (errno));
|
||||
#endif
|
||||
|
||||
if (pipe (sigterm_pipe_fds) != 0)
|
||||
g_printerr ("Failed to create SIGTERM pipe: %s\n",
|
||||
g_strerror (errno));
|
||||
|
||||
channel = g_io_channel_unix_new (sigterm_pipe_fds[0]);
|
||||
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
|
||||
g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_sigterm, NULL);
|
||||
g_io_channel_set_close_on_unref (channel, TRUE);
|
||||
g_io_channel_unref (channel);
|
||||
|
||||
act.sa_handler = &sigterm_handler;
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||
g_printerr ("Failed to register SIGTERM handler: %s\n",
|
||||
g_strerror (errno));
|
||||
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
|
||||
|
||||
if (g_getenv ("MUTTER_VERBOSE"))
|
||||
meta_set_verbose (TRUE);
|
||||
if (g_getenv ("MUTTER_DEBUG"))
|
||||
meta_set_debugging (TRUE);
|
||||
|
||||
if (opt_display_server)
|
||||
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
|
||||
|
||||
meta_set_is_wayland_compositor (opt_wayland);
|
||||
|
||||
if (g_get_home_dir ())
|
||||
if (chdir (g_get_home_dir ()) < 0)
|
||||
meta_warning ("Could not change to home directory %s.\n",
|
||||
@ -430,9 +358,16 @@ meta_init (void)
|
||||
g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
|
||||
#endif
|
||||
|
||||
meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
/* NB: When running as a hybrid wayland compositor we run our own headless X
|
||||
* server so the user can't control the X display to connect too. */
|
||||
meta_wayland_init ();
|
||||
}
|
||||
else
|
||||
meta_select_display (opt_display_name);
|
||||
|
||||
meta_select_display (opt_display_name);
|
||||
meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));
|
||||
|
||||
if (opt_replace_wm)
|
||||
meta_set_replace_current_wm (TRUE);
|
||||
@ -441,13 +376,20 @@ meta_init (void)
|
||||
meta_fatal ("Can't specify both SM save file and SM client id\n");
|
||||
|
||||
meta_main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
|
||||
meta_ui_init ();
|
||||
|
||||
/*
|
||||
* Clutter can only be initialized after the UI.
|
||||
*/
|
||||
meta_clutter_init ();
|
||||
/* If we are running with wayland then we don't wait until we have
|
||||
* an X connection before initializing clutter we instead initialize
|
||||
* it earlier since we need to initialize the GL driver so the driver
|
||||
* can register any needed wayland extensions. */
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
/*
|
||||
* Clutter can only be initialized after the UI.
|
||||
*/
|
||||
meta_clutter_init ();
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: We cannot handle high dpi scaling yet, so fix the scale to 1
|
||||
|
355
src/core/meta-accel-parse.c
Normal file
355
src/core/meta-accel-parse.c
Normal file
@ -0,0 +1,355 @@
|
||||
/* -*- 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-accel-parse.h"
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* This is copied from GTK+ and modified to work with mutter's
|
||||
* internal structures. Originating code comes from gtk/gtkaccelgroup.c
|
||||
*/
|
||||
|
||||
static inline gboolean
|
||||
is_alt (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'a' || string[1] == 'A') &&
|
||||
(string[2] == 'l' || string[2] == 'L') &&
|
||||
(string[3] == 't' || string[3] == 'T') &&
|
||||
(string[4] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_ctl (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'c' || string[1] == 'C') &&
|
||||
(string[2] == 't' || string[2] == 'T') &&
|
||||
(string[3] == 'l' || string[3] == 'L') &&
|
||||
(string[4] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_modx (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'm' || string[1] == 'M') &&
|
||||
(string[2] == 'o' || string[2] == 'O') &&
|
||||
(string[3] == 'd' || string[3] == 'D') &&
|
||||
(string[4] >= '1' && string[4] <= '5') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_ctrl (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'c' || string[1] == 'C') &&
|
||||
(string[2] == 't' || string[2] == 'T') &&
|
||||
(string[3] == 'r' || string[3] == 'R') &&
|
||||
(string[4] == 'l' || string[4] == 'L') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_shft (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 's' || string[1] == 'S') &&
|
||||
(string[2] == 'h' || string[2] == 'H') &&
|
||||
(string[3] == 'f' || string[3] == 'F') &&
|
||||
(string[4] == 't' || string[4] == 'T') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_shift (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 's' || string[1] == 'S') &&
|
||||
(string[2] == 'h' || string[2] == 'H') &&
|
||||
(string[3] == 'i' || string[3] == 'I') &&
|
||||
(string[4] == 'f' || string[4] == 'F') &&
|
||||
(string[5] == 't' || string[5] == 'T') &&
|
||||
(string[6] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_control (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'c' || string[1] == 'C') &&
|
||||
(string[2] == 'o' || string[2] == 'O') &&
|
||||
(string[3] == 'n' || string[3] == 'N') &&
|
||||
(string[4] == 't' || string[4] == 'T') &&
|
||||
(string[5] == 'r' || string[5] == 'R') &&
|
||||
(string[6] == 'o' || string[6] == 'O') &&
|
||||
(string[7] == 'l' || string[7] == 'L') &&
|
||||
(string[8] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_meta (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'm' || string[1] == 'M') &&
|
||||
(string[2] == 'e' || string[2] == 'E') &&
|
||||
(string[3] == 't' || string[3] == 'T') &&
|
||||
(string[4] == 'a' || string[4] == 'A') &&
|
||||
(string[5] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_super (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 's' || string[1] == 'S') &&
|
||||
(string[2] == 'u' || string[2] == 'U') &&
|
||||
(string[3] == 'p' || string[3] == 'P') &&
|
||||
(string[4] == 'e' || string[4] == 'E') &&
|
||||
(string[5] == 'r' || string[5] == 'R') &&
|
||||
(string[6] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_hyper (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'h' || string[1] == 'H') &&
|
||||
(string[2] == 'y' || string[2] == 'Y') &&
|
||||
(string[3] == 'p' || string[3] == 'P') &&
|
||||
(string[4] == 'e' || string[4] == 'E') &&
|
||||
(string[5] == 'r' || string[5] == 'R') &&
|
||||
(string[6] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_primary (const gchar *string)
|
||||
{
|
||||
return ((string[0] == '<') &&
|
||||
(string[1] == 'p' || string[1] == 'P') &&
|
||||
(string[2] == 'r' || string[2] == 'R') &&
|
||||
(string[3] == 'i' || string[3] == 'I') &&
|
||||
(string[4] == 'm' || string[4] == 'M') &&
|
||||
(string[5] == 'a' || string[5] == 'A') &&
|
||||
(string[6] == 'r' || string[6] == 'R') &&
|
||||
(string[7] == 'y' || string[7] == 'Y') &&
|
||||
(string[8] == '>'));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_keycode (const gchar *string)
|
||||
{
|
||||
return (string[0] == '0' &&
|
||||
string[1] == 'x' &&
|
||||
g_ascii_isxdigit (string[2]) &&
|
||||
g_ascii_isxdigit (string[3]));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
accelerator_parse (const gchar *accelerator,
|
||||
guint *accelerator_key,
|
||||
guint *accelerator_keycode,
|
||||
MetaVirtualModifier *accelerator_mods)
|
||||
{
|
||||
gboolean error = FALSE;
|
||||
guint keyval, keycode;
|
||||
MetaVirtualModifier mods;
|
||||
gint len;
|
||||
|
||||
if (accelerator_key)
|
||||
*accelerator_key = 0;
|
||||
if (accelerator_keycode)
|
||||
*accelerator_keycode = 0;
|
||||
if (accelerator_mods)
|
||||
*accelerator_mods = 0;
|
||||
|
||||
if (accelerator == NULL)
|
||||
{
|
||||
error = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
keyval = 0;
|
||||
mods = 0;
|
||||
len = strlen (accelerator);
|
||||
while (len)
|
||||
{
|
||||
if (*accelerator == '<')
|
||||
{
|
||||
if (len >= 9 && is_primary (accelerator))
|
||||
{
|
||||
/* Primary is treated the same as Control */
|
||||
accelerator += 9;
|
||||
len -= 9;
|
||||
mods |= META_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 9 && is_control (accelerator))
|
||||
{
|
||||
accelerator += 9;
|
||||
len -= 9;
|
||||
mods |= META_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 7 && is_shift (accelerator))
|
||||
{
|
||||
accelerator += 7;
|
||||
len -= 7;
|
||||
mods |= META_VIRTUAL_SHIFT_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_shft (accelerator))
|
||||
{
|
||||
accelerator += 6;
|
||||
len -= 6;
|
||||
mods |= META_VIRTUAL_SHIFT_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_ctrl (accelerator))
|
||||
{
|
||||
accelerator += 6;
|
||||
len -= 6;
|
||||
mods |= META_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_modx (accelerator))
|
||||
{
|
||||
static const guint mod_vals[] = {
|
||||
META_VIRTUAL_ALT_MASK,
|
||||
META_VIRTUAL_MOD2_MASK,
|
||||
META_VIRTUAL_MOD3_MASK,
|
||||
META_VIRTUAL_MOD4_MASK,
|
||||
META_VIRTUAL_MOD5_MASK,
|
||||
};
|
||||
|
||||
len -= 6;
|
||||
accelerator += 4;
|
||||
mods |= mod_vals[*accelerator - '1'];
|
||||
accelerator += 2;
|
||||
}
|
||||
else if (len >= 5 && is_ctl (accelerator))
|
||||
{
|
||||
accelerator += 5;
|
||||
len -= 5;
|
||||
mods |= META_VIRTUAL_CONTROL_MASK;
|
||||
}
|
||||
else if (len >= 5 && is_alt (accelerator))
|
||||
{
|
||||
accelerator += 5;
|
||||
len -= 5;
|
||||
mods |= META_VIRTUAL_ALT_MASK;
|
||||
}
|
||||
else if (len >= 6 && is_meta (accelerator))
|
||||
{
|
||||
accelerator += 6;
|
||||
len -= 6;
|
||||
mods |= META_VIRTUAL_META_MASK;
|
||||
}
|
||||
else if (len >= 7 && is_hyper (accelerator))
|
||||
{
|
||||
accelerator += 7;
|
||||
len -= 7;
|
||||
mods |= META_VIRTUAL_HYPER_MASK;
|
||||
}
|
||||
else if (len >= 7 && is_super (accelerator))
|
||||
{
|
||||
accelerator += 7;
|
||||
len -= 7;
|
||||
mods |= META_VIRTUAL_SUPER_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar last_ch;
|
||||
|
||||
last_ch = *accelerator;
|
||||
while (last_ch && last_ch != '>')
|
||||
{
|
||||
last_ch = *accelerator;
|
||||
accelerator += 1;
|
||||
len -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len >= 4 && is_keycode (accelerator))
|
||||
{
|
||||
keycode = strtoul (accelerator, NULL, 16);
|
||||
goto out;
|
||||
}
|
||||
else if (strcmp (accelerator, "Above_Tab") == 0)
|
||||
{
|
||||
keyval = META_KEY_ABOVE_TAB;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyval = xkb_keysym_from_name (accelerator, XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
if (keyval == XKB_KEY_NoSymbol)
|
||||
{
|
||||
error = TRUE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
accelerator += len;
|
||||
len -= len;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (error)
|
||||
return FALSE;
|
||||
|
||||
if (accelerator_key)
|
||||
*accelerator_key = keyval;
|
||||
if (accelerator_keycode)
|
||||
*accelerator_keycode = keycode;
|
||||
if (accelerator_mods)
|
||||
*accelerator_mods = mods;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_parse_accelerator (const char *accel,
|
||||
unsigned int *keysym,
|
||||
unsigned int *keycode,
|
||||
MetaVirtualModifier *mask)
|
||||
{
|
||||
if (!accel[0] || strcmp (accel, "disabled") == 0)
|
||||
return TRUE;
|
||||
|
||||
return accelerator_parse (accel, keysym, keycode, mask);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_parse_modifier (const char *accel,
|
||||
MetaVirtualModifier *mask)
|
||||
{
|
||||
if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0)
|
||||
return TRUE;
|
||||
|
||||
return accelerator_parse (accel, NULL, NULL, mask);
|
||||
}
|
43
src/core/meta-accel-parse.h
Normal file
43
src/core/meta-accel-parse.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- 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_ACCEL_PARSE_H
|
||||
#define META_ACCEL_PARSE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <meta/common.h>
|
||||
|
||||
/* Not a real key symbol but means "key above the tab key"; this is
|
||||
* used as the default keybinding for cycle_group.
|
||||
* 0x2xxxxxxx is a range not used by GDK or X. the remaining digits are
|
||||
* randomly chosen */
|
||||
#define META_KEY_ABOVE_TAB 0x2f7259c9
|
||||
|
||||
gboolean meta_parse_accelerator (const char *accel,
|
||||
unsigned int *keysym,
|
||||
unsigned int *keycode,
|
||||
MetaVirtualModifier *mask);
|
||||
gboolean meta_parse_modifier (const char *accel,
|
||||
MetaVirtualModifier *mask);
|
||||
|
||||
#endif /* META_ACCEL_PARSE_H */
|
@ -1,412 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Giovanni Campagna <gcampagn@redhat.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:cursor-tracker
|
||||
* @title: MetaCursorTracker
|
||||
* @short_description: Mutter cursor tracking helper
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/util.h>
|
||||
#include <meta/errors.h>
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "screen-private.h"
|
||||
|
||||
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
|
||||
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
|
||||
|
||||
struct _MetaCursorTracker {
|
||||
GObject parent_instance;
|
||||
|
||||
MetaScreen *screen;
|
||||
|
||||
gboolean is_showing;
|
||||
|
||||
CoglTexture2D *sprite;
|
||||
int hot_x, hot_y;
|
||||
};
|
||||
|
||||
struct _MetaCursorTrackerClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
CURSOR_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
static void
|
||||
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:
|
||||
glyph = XC_left_ptr;
|
||||
break;
|
||||
case META_CURSOR_NORTH_RESIZE:
|
||||
glyph = XC_top_side;
|
||||
break;
|
||||
case META_CURSOR_SOUTH_RESIZE:
|
||||
glyph = XC_bottom_side;
|
||||
break;
|
||||
case META_CURSOR_WEST_RESIZE:
|
||||
glyph = XC_left_side;
|
||||
break;
|
||||
case META_CURSOR_EAST_RESIZE:
|
||||
glyph = XC_right_side;
|
||||
break;
|
||||
case META_CURSOR_SE_RESIZE:
|
||||
glyph = XC_bottom_right_corner;
|
||||
break;
|
||||
case META_CURSOR_SW_RESIZE:
|
||||
glyph = XC_bottom_left_corner;
|
||||
break;
|
||||
case META_CURSOR_NE_RESIZE:
|
||||
glyph = XC_top_right_corner;
|
||||
break;
|
||||
case META_CURSOR_NW_RESIZE:
|
||||
glyph = XC_top_left_corner;
|
||||
break;
|
||||
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
|
||||
glyph = XC_fleur;
|
||||
break;
|
||||
case META_CURSOR_BUSY:
|
||||
glyph = XC_watch;
|
||||
break;
|
||||
case META_CURSOR_DND_IN_DRAG:
|
||||
name = "dnd-none";
|
||||
break;
|
||||
case META_CURSOR_DND_MOVE:
|
||||
name = "dnd-move";
|
||||
break;
|
||||
case META_CURSOR_DND_COPY:
|
||||
name = "dnd-copy";
|
||||
break;
|
||||
case META_CURSOR_DND_UNSUPPORTED_TARGET:
|
||||
name = "dnd-none";
|
||||
break;
|
||||
case META_CURSOR_POINTING_HAND:
|
||||
glyph = XC_hand2;
|
||||
break;
|
||||
case META_CURSOR_CROSSHAIR:
|
||||
glyph = XC_crosshair;
|
||||
break;
|
||||
case META_CURSOR_IBEAM:
|
||||
glyph = XC_xterm;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
glyph = 0; /* silence compiler */
|
||||
break;
|
||||
}
|
||||
|
||||
*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_display_create_x_cursor (MetaDisplay *display,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
return load_cursor_on_server (display, cursor);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_init (MetaCursorTracker *self)
|
||||
{
|
||||
/* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of
|
||||
* detecting if the system mouse cursor is showing or not.
|
||||
*
|
||||
* On wayland we start with the cursor showing
|
||||
*/
|
||||
self->is_showing = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_finalize (GObject *object)
|
||||
{
|
||||
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
|
||||
|
||||
if (self->sprite)
|
||||
cogl_object_unref (self->sprite);
|
||||
|
||||
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_cursor_tracker_finalize;
|
||||
|
||||
signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static MetaCursorTracker *
|
||||
make_x11_cursor_tracker (MetaScreen *screen)
|
||||
{
|
||||
MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
|
||||
self->screen = screen;
|
||||
|
||||
XFixesSelectCursorInput (screen->display->xdisplay,
|
||||
screen->xroot,
|
||||
XFixesDisplayCursorNotifyMask);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_for_screen:
|
||||
* @screen: the #MetaScreen
|
||||
*
|
||||
* Retrieves the cursor tracker object for @screen.
|
||||
*
|
||||
* Returns: (transfer none):
|
||||
*/
|
||||
MetaCursorTracker *
|
||||
meta_cursor_tracker_get_for_screen (MetaScreen *screen)
|
||||
{
|
||||
MetaCursorTracker *self;
|
||||
|
||||
if (screen->cursor_tracker)
|
||||
return screen->cursor_tracker;
|
||||
|
||||
self = make_x11_cursor_tracker (screen);
|
||||
|
||||
screen->cursor_tracker = self;
|
||||
return self;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
|
||||
XEvent *xevent)
|
||||
{
|
||||
XFixesCursorNotifyEvent *notify_event;
|
||||
|
||||
if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify)
|
||||
return FALSE;
|
||||
|
||||
notify_event = (XFixesCursorNotifyEvent *)xevent;
|
||||
if (notify_event->subtype != XFixesDisplayCursorNotify)
|
||||
return FALSE;
|
||||
|
||||
g_clear_pointer (&tracker->sprite, cogl_object_unref);
|
||||
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
XFixesCursorImage *cursor_image;
|
||||
CoglTexture2D *sprite;
|
||||
guint8 *cursor_data;
|
||||
gboolean free_cursor_data;
|
||||
CoglContext *ctx;
|
||||
|
||||
if (tracker->sprite)
|
||||
return;
|
||||
|
||||
cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay);
|
||||
if (!cursor_image)
|
||||
return;
|
||||
|
||||
/* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
|
||||
* quantities as arrays of long; we need to convert on 64 bit */
|
||||
if (sizeof(long) == 4)
|
||||
{
|
||||
cursor_data = (guint8 *)cursor_image->pixels;
|
||||
free_cursor_data = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, j;
|
||||
guint32 *cursor_words;
|
||||
gulong *p;
|
||||
guint32 *q;
|
||||
|
||||
cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
|
||||
cursor_data = (guint8 *)cursor_words;
|
||||
|
||||
p = cursor_image->pixels;
|
||||
q = cursor_words;
|
||||
for (j = 0; j < cursor_image->height; j++)
|
||||
for (i = 0; i < cursor_image->width; i++)
|
||||
*(q++) = *(p++);
|
||||
|
||||
free_cursor_data = TRUE;
|
||||
}
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
sprite = cogl_texture_2d_new_from_data (ctx,
|
||||
cursor_image->width,
|
||||
cursor_image->height,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
cursor_image->width * 4, /* stride */
|
||||
cursor_data,
|
||||
NULL);
|
||||
|
||||
if (free_cursor_data)
|
||||
g_free (cursor_data);
|
||||
|
||||
if (sprite != NULL)
|
||||
{
|
||||
tracker->sprite = sprite;
|
||||
tracker->hot_x = cursor_image->xhot;
|
||||
tracker->hot_y = cursor_image->yhot;
|
||||
}
|
||||
XFree (cursor_image);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_sprite:
|
||||
*
|
||||
* Returns: (transfer none):
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
|
||||
|
||||
ensure_xfixes_cursor (tracker);
|
||||
|
||||
return COGL_TEXTURE (tracker->sprite);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_cursor_tracker_get_hot:
|
||||
* @tracker:
|
||||
* @x: (out):
|
||||
* @y: (out):
|
||||
*
|
||||
*/
|
||||
void
|
||||
meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
||||
int *x,
|
||||
int *y)
|
||||
{
|
||||
g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
|
||||
|
||||
ensure_xfixes_cursor (tracker);
|
||||
|
||||
if (x)
|
||||
*x = tracker->hot_x;
|
||||
if (y)
|
||||
*y = tracker->hot_y;
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
Cursor xcursor;
|
||||
MetaDisplay *display = tracker->screen->display;
|
||||
|
||||
/* First create a cursor for X11 applications that don't specify their own */
|
||||
xcursor = meta_display_create_x_cursor (display, cursor);
|
||||
|
||||
XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor);
|
||||
XFlush (display->xdisplay);
|
||||
XFreeCursor (display->xdisplay, xcursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
|
||||
int *x,
|
||||
int *y,
|
||||
ClutterModifierType *mods)
|
||||
{
|
||||
GdkDeviceManager *gmanager;
|
||||
GdkDevice *gdevice;
|
||||
GdkScreen *gscreen;
|
||||
|
||||
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);
|
||||
gdk_device_get_state (gdevice,
|
||||
gdk_screen_get_root_window (gscreen),
|
||||
NULL, (GdkModifierType*)mods);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
|
||||
gboolean visible)
|
||||
{
|
||||
if (visible == tracker->is_showing)
|
||||
return;
|
||||
tracker->is_showing = visible;
|
||||
|
||||
if (visible)
|
||||
XFixesShowCursor (tracker->screen->display->xdisplay,
|
||||
tracker->screen->xroot);
|
||||
else
|
||||
XFixesHideCursor (tracker->screen->display->xdisplay,
|
||||
tracker->screen->xroot);
|
||||
}
|
@ -1,889 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:idle-monitor
|
||||
* @title: MetaIdleMonitor
|
||||
* @short_description: Mutter idle counter (similar to X's IDLETIME)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
#include <meta/util.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "display-private.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-dbus-idle-monitor.h"
|
||||
|
||||
G_STATIC_ASSERT(sizeof(unsigned long) == sizeof(gpointer));
|
||||
|
||||
struct _MetaIdleMonitor
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *watches;
|
||||
GHashTable *alarms;
|
||||
int device_id;
|
||||
|
||||
/* X11 implementation */
|
||||
Display *display;
|
||||
int sync_event_base;
|
||||
XSyncCounter counter;
|
||||
XSyncAlarm user_active_alarm;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
guint id;
|
||||
MetaIdleMonitorWatchFunc callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
guint64 timeout_msec;
|
||||
|
||||
/* x11 */
|
||||
XSyncAlarm xalarm;
|
||||
int idle_source_id;
|
||||
} MetaIdleMonitorWatch;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DEVICE_ID,
|
||||
PROP_LAST,
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST];
|
||||
|
||||
G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT)
|
||||
|
||||
static MetaIdleMonitor *device_monitors[256];
|
||||
static int device_id_max;
|
||||
|
||||
static gint64
|
||||
_xsyncvalue_to_int64 (XSyncValue value)
|
||||
{
|
||||
return ((guint64) XSyncValueHigh32 (value)) << 32
|
||||
| (guint64) XSyncValueLow32 (value);
|
||||
}
|
||||
|
||||
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
|
||||
|
||||
static void
|
||||
fire_watch (MetaIdleMonitorWatch *watch)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
guint id;
|
||||
gboolean is_user_active_watch;
|
||||
|
||||
monitor = watch->monitor;
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
id = watch->id;
|
||||
is_user_active_watch = (watch->timeout_msec == 0);
|
||||
|
||||
if (watch->callback)
|
||||
watch->callback (monitor, id, watch->user_data);
|
||||
|
||||
if (is_user_active_watch)
|
||||
meta_idle_monitor_remove_watch (monitor, id);
|
||||
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
|
||||
static XSyncAlarm
|
||||
_xsync_alarm_set (MetaIdleMonitor *monitor,
|
||||
XSyncTestType test_type,
|
||||
guint64 interval,
|
||||
gboolean want_events)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
XSyncValue delta;
|
||||
guint flags;
|
||||
|
||||
flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType |
|
||||
XSyncCAValue | XSyncCADelta | XSyncCAEvents;
|
||||
|
||||
XSyncIntToValue (&delta, 0);
|
||||
attr.trigger.counter = monitor->counter;
|
||||
attr.trigger.value_type = XSyncAbsolute;
|
||||
attr.delta = delta;
|
||||
attr.events = want_events;
|
||||
|
||||
GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
|
||||
attr.trigger.test_type = test_type;
|
||||
return XSyncCreateAlarm (monitor->display, flags, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_alarm_rescheduled (Display *dpy,
|
||||
XSyncAlarm alarm)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
|
||||
/* Some versions of Xorg have an issue where alarms aren't
|
||||
* always rescheduled. Calling XSyncChangeAlarm, even
|
||||
* without any attributes, will reschedule the alarm. */
|
||||
XSyncChangeAlarm (dpy, alarm, 0, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
set_alarm_enabled (Display *dpy,
|
||||
XSyncAlarm alarm,
|
||||
gboolean enabled)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
attr.events = enabled;
|
||||
XSyncChangeAlarm (dpy, alarm, XSyncCAEvents, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
check_x11_watch (gpointer data,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = data;
|
||||
XSyncAlarm alarm = (XSyncAlarm) user_data;
|
||||
|
||||
if (watch->xalarm != alarm)
|
||||
return;
|
||||
|
||||
fire_watch (watch);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_handle_xevent (MetaIdleMonitor *monitor,
|
||||
XSyncAlarmNotifyEvent *alarm_event)
|
||||
{
|
||||
XSyncAlarm alarm;
|
||||
GList *watches;
|
||||
gboolean has_alarm;
|
||||
|
||||
if (alarm_event->state != XSyncAlarmActive)
|
||||
return;
|
||||
|
||||
alarm = alarm_event->alarm;
|
||||
|
||||
has_alarm = FALSE;
|
||||
|
||||
if (alarm == monitor->user_active_alarm)
|
||||
{
|
||||
set_alarm_enabled (monitor->display,
|
||||
alarm,
|
||||
FALSE);
|
||||
has_alarm = TRUE;
|
||||
}
|
||||
else if (g_hash_table_contains (monitor->alarms, (gpointer) alarm))
|
||||
{
|
||||
ensure_alarm_rescheduled (monitor->display,
|
||||
alarm);
|
||||
has_alarm = TRUE;
|
||||
}
|
||||
|
||||
if (has_alarm)
|
||||
{
|
||||
watches = g_hash_table_get_values (monitor->watches);
|
||||
|
||||
g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
|
||||
g_list_free (watches);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_handle_xevent_all (XEvent *xevent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= device_id_max; i++)
|
||||
if (device_monitors[i])
|
||||
meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent);
|
||||
}
|
||||
|
||||
static char *
|
||||
counter_name_for_device (int device_id)
|
||||
{
|
||||
if (device_id > 0)
|
||||
return g_strdup_printf ("DEVICEIDLETIME %d", device_id);
|
||||
|
||||
return g_strdup ("IDLETIME");
|
||||
}
|
||||
|
||||
static XSyncCounter
|
||||
find_idletime_counter (MetaIdleMonitor *monitor)
|
||||
{
|
||||
int i;
|
||||
int ncounters;
|
||||
XSyncSystemCounter *counters;
|
||||
XSyncCounter counter = None;
|
||||
char *counter_name;
|
||||
|
||||
counter_name = counter_name_for_device (monitor->device_id);
|
||||
counters = XSyncListSystemCounters (monitor->display, &ncounters);
|
||||
for (i = 0; i < ncounters; i++)
|
||||
{
|
||||
if (counters[i].name != NULL && strcmp (counters[i].name, counter_name) == 0)
|
||||
{
|
||||
counter = counters[i].counter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XSyncFreeSystemCounterList (counters);
|
||||
g_free (counter_name);
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
static guint32 serial = 0;
|
||||
g_atomic_int_inc (&serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static void
|
||||
idle_monitor_watch_free (MetaIdleMonitorWatch *watch)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
|
||||
if (watch == NULL)
|
||||
return;
|
||||
|
||||
monitor = watch->monitor;
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
if (watch->notify != NULL)
|
||||
watch->notify (watch->user_data);
|
||||
|
||||
if (watch->xalarm != monitor->user_active_alarm &&
|
||||
watch->xalarm != None)
|
||||
{
|
||||
XSyncDestroyAlarm (monitor->display, watch->xalarm);
|
||||
g_hash_table_remove (monitor->alarms, (gpointer) watch->xalarm);
|
||||
}
|
||||
|
||||
g_object_unref (monitor);
|
||||
g_slice_free (MetaIdleMonitorWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
init_xsync (MetaIdleMonitor *monitor)
|
||||
{
|
||||
monitor->counter = find_idletime_counter (monitor);
|
||||
/* IDLETIME counter not found? */
|
||||
if (monitor->counter == None)
|
||||
{
|
||||
meta_warning ("IDLETIME counter not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_dispose (GObject *object)
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
|
||||
monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
g_clear_pointer (&monitor->watches, g_hash_table_destroy);
|
||||
g_clear_pointer (&monitor->alarms, g_hash_table_destroy);
|
||||
|
||||
if (monitor->user_active_alarm != None)
|
||||
{
|
||||
XSyncDestroyAlarm (monitor->display, monitor->user_active_alarm);
|
||||
monitor->user_active_alarm = None;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE_ID:
|
||||
g_value_set_int (value, monitor->device_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE_ID:
|
||||
monitor->device_id = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_constructed (GObject *object)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
monitor->display = meta_get_display ()->xdisplay;
|
||||
init_xsync (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_idle_monitor_dispose;
|
||||
object_class->constructed = meta_idle_monitor_constructed;
|
||||
object_class->get_property = meta_idle_monitor_get_property;
|
||||
object_class->set_property = meta_idle_monitor_set_property;
|
||||
|
||||
/**
|
||||
* MetaIdleMonitor:device_id:
|
||||
*
|
||||
* The device to listen to idletime on.
|
||||
*/
|
||||
obj_props[PROP_DEVICE_ID] =
|
||||
g_param_spec_int ("device-id",
|
||||
"Device ID",
|
||||
"The device to listen to idletime on",
|
||||
0, 255, 0,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_init (MetaIdleMonitor *monitor)
|
||||
{
|
||||
monitor->watches = g_hash_table_new_full (NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GDestroyNotify)idle_monitor_watch_free);
|
||||
|
||||
monitor->alarms = g_hash_table_new (NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_device_monitor (int device_id)
|
||||
{
|
||||
if (device_monitors[device_id])
|
||||
return;
|
||||
|
||||
device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL);
|
||||
device_id_max = MAX (device_id_max, device_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_core:
|
||||
*
|
||||
* Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global
|
||||
* idletime for all devices. To track device-specific idletime,
|
||||
* use meta_idle_monitor_get_for_device().
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_idle_monitor_get_core (void)
|
||||
{
|
||||
ensure_device_monitor (0);
|
||||
return device_monitors[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_for_device:
|
||||
* @device_id: the device to get the idle time for.
|
||||
*
|
||||
* Returns: (transfer none): a new #MetaIdleMonitor that tracks the
|
||||
* device-specific idletime for @device. To track server-global idletime
|
||||
* for all devices, use meta_idle_monitor_get_core().
|
||||
*/
|
||||
MetaIdleMonitor *
|
||||
meta_idle_monitor_get_for_device (int device_id)
|
||||
{
|
||||
g_return_val_if_fail (device_id > 0 && device_id < 256, NULL);
|
||||
|
||||
ensure_device_monitor (device_id);
|
||||
return device_monitors[device_id];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fire_watch_idle (gpointer data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = data;
|
||||
|
||||
watch->idle_source_id = 0;
|
||||
fire_watch (watch);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
watch = g_slice_new0 (MetaIdleMonitorWatch);
|
||||
watch->monitor = monitor;
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
watch->timeout_msec = timeout_msec;
|
||||
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE);
|
||||
|
||||
g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm);
|
||||
|
||||
if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec)
|
||||
watch->idle_source_id = g_idle_add (fire_watch_idle, watch);
|
||||
}
|
||||
else if (monitor->user_active_alarm != None)
|
||||
{
|
||||
watch->xalarm = monitor->user_active_alarm;
|
||||
|
||||
set_alarm_enabled (monitor->display, monitor->user_active_alarm, TRUE);
|
||||
}
|
||||
|
||||
g_hash_table_insert (monitor->watches,
|
||||
GUINT_TO_POINTER (watch->id),
|
||||
watch);
|
||||
return watch;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_add_idle_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @interval_msec: The idletime interval, in milliseconds
|
||||
* @callback: (allow-none): The callback to call when the user has
|
||||
* accumulated @interval_msec milliseconds of idle time.
|
||||
* @user_data: (allow-none): The user data to pass to the callback
|
||||
* @notify: A #GDestroyNotify
|
||||
*
|
||||
* Returns: a watch id
|
||||
*
|
||||
* Adds a watch for a specific idle time. The callback will be called
|
||||
* when the user has accumulated @interval_msec milliseconds of idle time.
|
||||
* This function will return an ID that can either be passed to
|
||||
* meta_idle_monitor_remove_watch(), or can be used to tell idle time
|
||||
* watches apart if you have more than one.
|
||||
*
|
||||
* Also note that this function will only care about positive transitions
|
||||
* (user's idle time exceeding a certain time). If you want to know about
|
||||
* when the user has become active, use
|
||||
* meta_idle_monitor_add_user_active_watch().
|
||||
*/
|
||||
guint
|
||||
meta_idle_monitor_add_idle_watch (MetaIdleMonitor *monitor,
|
||||
guint64 interval_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
|
||||
g_return_val_if_fail (interval_msec > 0, 0);
|
||||
|
||||
watch = make_watch (monitor,
|
||||
interval_msec,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_add_user_active_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @callback: (allow-none): The callback to call when the user is
|
||||
* active again.
|
||||
* @user_data: (allow-none): The user data to pass to the callback
|
||||
* @notify: A #GDestroyNotify
|
||||
*
|
||||
* Returns: a watch id
|
||||
*
|
||||
* Add a one-time watch to know when the user is active again.
|
||||
* Note that this watch is one-time and will de-activate after the
|
||||
* function is called, for efficiency purposes. It's most convenient
|
||||
* to call this when an idle watch, as added by
|
||||
* meta_idle_monitor_add_idle_watch(), has triggered.
|
||||
*/
|
||||
guint
|
||||
meta_idle_monitor_add_user_active_watch (MetaIdleMonitor *monitor,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
g_return_val_if_fail (META_IS_IDLE_MONITOR (monitor), 0);
|
||||
|
||||
watch = make_watch (monitor,
|
||||
0,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
|
||||
return watch->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_remove_watch:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
* @id: A watch ID
|
||||
*
|
||||
* Removes an idle time watcher, previously added by
|
||||
* meta_idle_monitor_add_idle_watch() or
|
||||
* meta_idle_monitor_add_user_active_watch().
|
||||
*/
|
||||
void
|
||||
meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
|
||||
guint id)
|
||||
{
|
||||
g_return_if_fail (META_IS_IDLE_MONITOR (monitor));
|
||||
|
||||
g_object_ref (monitor);
|
||||
g_hash_table_remove (monitor->watches,
|
||||
GUINT_TO_POINTER (id));
|
||||
g_object_unref (monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_idle_monitor_get_idletime:
|
||||
* @monitor: A #MetaIdleMonitor
|
||||
*
|
||||
* Returns: The current idle time, in milliseconds, or -1 for not supported
|
||||
*/
|
||||
gint64
|
||||
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
XSyncValue value;
|
||||
|
||||
if (!XSyncQueryCounter (monitor->display, monitor->counter, &value))
|
||||
return -1;
|
||||
|
||||
return _xsyncvalue_to_int64 (value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_get_idletime (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
guint64 idletime;
|
||||
|
||||
idletime = meta_idle_monitor_get_idletime (monitor);
|
||||
meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaDBusIdleMonitor *dbus_monitor;
|
||||
MetaIdleMonitor *monitor;
|
||||
char *dbus_name;
|
||||
guint watch_id;
|
||||
guint name_watcher_id;
|
||||
} DBusWatch;
|
||||
|
||||
static void
|
||||
destroy_dbus_watch (gpointer data)
|
||||
{
|
||||
DBusWatch *watch = data;
|
||||
|
||||
g_object_unref (watch->dbus_monitor);
|
||||
g_object_unref (watch->monitor);
|
||||
g_free (watch->dbus_name);
|
||||
g_bus_unwatch_name (watch->name_watcher_id);
|
||||
|
||||
g_slice_free (DBusWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_idle_callback (MetaIdleMonitor *monitor,
|
||||
guint watch_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
DBusWatch *watch = user_data;
|
||||
GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor);
|
||||
|
||||
g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton),
|
||||
watch->dbus_name,
|
||||
g_dbus_interface_skeleton_get_object_path (skeleton),
|
||||
"org.gnome.Mutter.IdleMonitor",
|
||||
"WatchFired",
|
||||
g_variant_new ("(u)", watch_id),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
name_vanished_callback (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
DBusWatch *watch = user_data;
|
||||
|
||||
meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id);
|
||||
}
|
||||
|
||||
static DBusWatch *
|
||||
make_dbus_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = g_slice_new (DBusWatch);
|
||||
watch->dbus_monitor = g_object_ref (skeleton);
|
||||
watch->monitor = g_object_ref (monitor);
|
||||
watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
|
||||
watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
|
||||
watch->dbus_name,
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
NULL, /* appeared */
|
||||
name_vanished_callback,
|
||||
watch, NULL);
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_idle_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint64 interval,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = make_dbus_watch (skeleton, invocation, monitor);
|
||||
watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval,
|
||||
dbus_idle_callback, watch, destroy_dbus_watch);
|
||||
|
||||
meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
DBusWatch *watch;
|
||||
|
||||
watch = make_dbus_watch (skeleton, invocation, monitor);
|
||||
watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor,
|
||||
dbus_idle_callback, watch,
|
||||
destroy_dbus_watch);
|
||||
|
||||
meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_remove_watch (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint id,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
meta_idle_monitor_remove_watch (monitor, id);
|
||||
meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
create_monitor_skeleton (GDBusObjectManagerServer *manager,
|
||||
MetaIdleMonitor *monitor,
|
||||
const char *path)
|
||||
{
|
||||
MetaDBusIdleMonitor *skeleton;
|
||||
MetaDBusObjectSkeleton *object;
|
||||
|
||||
skeleton = meta_dbus_idle_monitor_skeleton_new ();
|
||||
g_signal_connect_object (skeleton, "handle-add-idle-watch",
|
||||
G_CALLBACK (handle_add_idle_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-add-user-active-watch",
|
||||
G_CALLBACK (handle_add_user_active_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-remove-watch",
|
||||
G_CALLBACK (handle_remove_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-get-idletime",
|
||||
G_CALLBACK (handle_get_idletime), monitor, 0);
|
||||
|
||||
object = meta_dbus_object_skeleton_new (path);
|
||||
meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
|
||||
|
||||
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_added (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
GDBusObjectManagerServer *manager)
|
||||
{
|
||||
|
||||
MetaIdleMonitor *monitor;
|
||||
int device_id;
|
||||
char *path;
|
||||
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
monitor = meta_idle_monitor_get_for_device (device_id);
|
||||
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
|
||||
|
||||
create_monitor_skeleton (manager, monitor, path);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
on_device_removed (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device,
|
||||
GDBusObjectManagerServer *manager)
|
||||
{
|
||||
int device_id;
|
||||
char *path;
|
||||
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
|
||||
g_dbus_object_manager_server_unexport (manager, path);
|
||||
g_free (path);
|
||||
|
||||
g_clear_object (&device_monitors[device_id]);
|
||||
if (device_id == device_id_max)
|
||||
device_id_max--;
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusObjectManagerServer *manager;
|
||||
ClutterDeviceManager *device_manager;
|
||||
MetaIdleMonitor *monitor;
|
||||
GSList *devices, *iter;
|
||||
char *path;
|
||||
|
||||
manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
|
||||
|
||||
/* We never clear the core monitor, as that's supposed to cumulate idle times from
|
||||
all devices */
|
||||
monitor = meta_idle_monitor_get_core ();
|
||||
path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
|
||||
create_monitor_skeleton (manager, monitor, path);
|
||||
g_free (path);
|
||||
|
||||
device_manager = clutter_device_manager_get_default ();
|
||||
devices = clutter_device_manager_list_devices (device_manager);
|
||||
|
||||
for (iter = devices; iter; iter = iter->next)
|
||||
on_device_added (device_manager, iter->data, manager);
|
||||
|
||||
g_slist_free (devices);
|
||||
|
||||
g_signal_connect_object (device_manager, "device-added",
|
||||
G_CALLBACK (on_device_added), manager, 0);
|
||||
g_signal_connect_object (device_manager, "device-removed",
|
||||
G_CALLBACK (on_device_removed), manager, 0);
|
||||
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_verbose ("Acquired name %s\n", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
meta_verbose ("Lost or failed to acquire name %s\n", name);
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_init_dbus (void)
|
||||
{
|
||||
static int dbus_name_id;
|
||||
|
||||
if (dbus_name_id > 0)
|
||||
return;
|
||||
|
||||
dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gnome.Mutter.IdleMonitor",
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
||||
(meta_get_replace_current_wm () ?
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
|
||||
/* denied_focus_and_not_transient is only set when focus_window != NULL */
|
||||
|
||||
if (window->denied_focus_and_not_transient &&
|
||||
window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
|
||||
window->type == META_WINDOW_MODAL_DIALOG &&
|
||||
meta_window_same_application (window, focus_window) &&
|
||||
window_overlaps_focus_window (window))
|
||||
{
|
||||
@ -610,7 +610,7 @@ meta_window_place (MetaWindow *window,
|
||||
meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc);
|
||||
|
||||
windows = NULL;
|
||||
|
||||
|
||||
switch (window->type)
|
||||
{
|
||||
/* Run placement algorithm on these. */
|
||||
@ -638,7 +638,7 @@ meta_window_place (MetaWindow *window,
|
||||
case META_WINDOW_OVERRIDE_OTHER:
|
||||
goto done_no_constraints;
|
||||
}
|
||||
|
||||
|
||||
if (meta_prefs_get_disable_workarounds ())
|
||||
{
|
||||
switch (window->type)
|
||||
@ -699,18 +699,11 @@ meta_window_place (MetaWindow *window,
|
||||
goto done_no_constraints;
|
||||
}
|
||||
}
|
||||
|
||||
if ((window->type == META_WINDOW_DIALOG ||
|
||||
window->type == META_WINDOW_MODAL_DIALOG) &&
|
||||
window->xtransient_for != None)
|
||||
{
|
||||
/* Center horizontally, at top of parent vertically */
|
||||
|
||||
MetaWindow *parent;
|
||||
|
||||
parent =
|
||||
meta_display_lookup_x_window (window->display,
|
||||
window->xtransient_for);
|
||||
if (window->type == META_WINDOW_DIALOG ||
|
||||
window->type == META_WINDOW_MODAL_DIALOG)
|
||||
{
|
||||
MetaWindow *parent = meta_window_get_transient_for (window);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "keybindings-private.h"
|
||||
#include "meta-accel-parse.h"
|
||||
|
||||
/* If you add a key, it needs updating in init() and in the gsettings
|
||||
* notify listener and of course in the .schemas file.
|
||||
@ -1187,8 +1188,8 @@ maybe_give_disable_workarounds_warning (void)
|
||||
{
|
||||
first_disable = FALSE;
|
||||
|
||||
meta_warning (_("Workarounds for broken applications disabled. "
|
||||
"Some applications may not behave properly.\n"));
|
||||
meta_warning ("Workarounds for broken applications disabled. "
|
||||
"Some applications may not behave properly.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1262,8 +1263,8 @@ titlebar_handler (GVariant *value,
|
||||
|
||||
if (desc == NULL)
|
||||
{
|
||||
meta_warning (_("Could not parse font description "
|
||||
"\"%s\" from GSettings key %s\n"),
|
||||
meta_warning ("Could not parse font description "
|
||||
"\"%s\" from GSettings key %s\n",
|
||||
string_value ? string_value : "(null)",
|
||||
KEY_TITLEBAR_FONT);
|
||||
return FALSE;
|
||||
@ -1323,13 +1324,13 @@ mouse_button_mods_handler (GVariant *value,
|
||||
*result = NULL; /* ignored */
|
||||
string_value = g_variant_get_string (value, NULL);
|
||||
|
||||
if (!string_value || !meta_ui_parse_modifier (string_value, &mods))
|
||||
if (!string_value || !meta_parse_modifier (string_value, &mods))
|
||||
{
|
||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||
"Failed to parse new GSettings value\n");
|
||||
|
||||
meta_warning (_("\"%s\" found in configuration database is "
|
||||
"not a valid value for mouse button modifier\n"),
|
||||
meta_warning ("\"%s\" found in configuration database is "
|
||||
"not a valid value for mouse button modifier\n",
|
||||
string_value);
|
||||
|
||||
return FALSE;
|
||||
@ -1627,9 +1628,9 @@ overlay_key_handler (GVariant *value,
|
||||
*result = NULL; /* ignored */
|
||||
string_value = g_variant_get_string (value, NULL);
|
||||
|
||||
if (string_value && meta_ui_parse_accelerator (string_value, &combo.keysym,
|
||||
&combo.keycode,
|
||||
&combo.modifiers))
|
||||
if (string_value && meta_parse_accelerator (string_value, &combo.keysym,
|
||||
&combo.keycode,
|
||||
&combo.modifiers))
|
||||
;
|
||||
else
|
||||
{
|
||||
@ -1887,11 +1888,11 @@ update_binding (MetaKeyPref *binding,
|
||||
keycode = 0;
|
||||
mods = 0;
|
||||
|
||||
if (!meta_ui_parse_accelerator (strokes[i], &keysym, &keycode, &mods))
|
||||
if (!meta_parse_accelerator (strokes[i], &keysym, &keycode, &mods))
|
||||
{
|
||||
meta_topic (META_DEBUG_KEYBINDINGS,
|
||||
"Failed to parse new GSettings value\n");
|
||||
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
|
||||
meta_warning ("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n",
|
||||
strokes[i], binding->name);
|
||||
|
||||
/* Value is kept and will thus be removed next time we save the key.
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include <X11/Xutil.h>
|
||||
#include "stack-tracker.h"
|
||||
#include "ui.h"
|
||||
#include "monitor-private.h"
|
||||
#include "meta-monitor-manager.h"
|
||||
|
||||
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
|
||||
gpointer user_data);
|
||||
@ -82,8 +82,6 @@ struct _MetaScreen
|
||||
MetaCursorTracker *cursor_tracker;
|
||||
MetaCursor current_cursor;
|
||||
|
||||
Window flash_window;
|
||||
|
||||
Window wm_sn_selection_window;
|
||||
Atom wm_sn_atom;
|
||||
guint32 wm_sn_timestamp;
|
||||
@ -118,9 +116,6 @@ struct _MetaScreen
|
||||
guint all_keys_grabbed : 1;
|
||||
|
||||
int closing;
|
||||
|
||||
/* Managed by compositor.c */
|
||||
gpointer compositor_data;
|
||||
|
||||
/* Instead of unmapping withdrawn windows we can leave them mapped
|
||||
* and restack them below a guard window. When using a compositor
|
||||
@ -223,12 +218,14 @@ void meta_screen_workspace_switched (MetaScreen *screen,
|
||||
|
||||
void meta_screen_set_active_workspace_hint (MetaScreen *screen);
|
||||
|
||||
void meta_screen_create_guard_window (MetaScreen *screen);
|
||||
|
||||
gboolean meta_screen_handle_xevent (MetaScreen *screen,
|
||||
XEvent *xevent);
|
||||
|
||||
int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
|
||||
int index);
|
||||
int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
|
||||
int index);
|
||||
|
||||
gboolean meta_screen_handle_xevent (MetaScreen *screen,
|
||||
XEvent *xevent);
|
||||
|
||||
#endif
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include "workspace-private.h"
|
||||
#include "keybindings-private.h"
|
||||
#include "stack.h"
|
||||
#include "xprops.h"
|
||||
#include <meta/compositor.h>
|
||||
#include "mutter-enum-types.h"
|
||||
#include "core.h"
|
||||
@ -53,6 +52,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "x11/xprops.h"
|
||||
|
||||
static char* get_screen_name (MetaDisplay *display,
|
||||
int number);
|
||||
|
||||
@ -454,6 +455,7 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
XSetWindowAttributes attributes;
|
||||
Window guard_window;
|
||||
gulong create_serial;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
attributes.event_mask = NoEventMask;
|
||||
attributes.override_redirect = True;
|
||||
@ -488,12 +490,14 @@ create_guard_window (Display *xdisplay, MetaScreen *screen)
|
||||
XISelectEvents (xdisplay, guard_window, &mask, 1);
|
||||
}
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = guard_window;
|
||||
meta_stack_tracker_record_add (screen->stack_tracker,
|
||||
guard_window,
|
||||
&stack_window,
|
||||
create_serial);
|
||||
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
guard_window,
|
||||
&stack_window,
|
||||
XNextRequest (xdisplay));
|
||||
XLowerWindow (xdisplay, guard_window);
|
||||
XMapWindow (xdisplay, guard_window);
|
||||
@ -559,7 +563,7 @@ meta_screen_new (MetaDisplay *display,
|
||||
}
|
||||
|
||||
/* We want to find out when the current selection owner dies */
|
||||
meta_error_trap_push_with_return (display);
|
||||
meta_error_trap_push (display);
|
||||
attrs.event_mask = StructureNotifyMask;
|
||||
XChangeWindowAttributes (xdisplay,
|
||||
current_wm_sn_owner, CWEventMask, &attrs);
|
||||
@ -579,7 +583,7 @@ meta_screen_new (MetaDisplay *display,
|
||||
|
||||
if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
|
||||
{
|
||||
meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"),
|
||||
meta_warning ("Could not acquire window manager selection on screen %d display \"%s\"\n",
|
||||
number, display->name);
|
||||
|
||||
XDestroyWindow (xdisplay, new_wm_sn_owner);
|
||||
@ -618,7 +622,7 @@ meta_screen_new (MetaDisplay *display,
|
||||
}
|
||||
|
||||
/* select our root window events */
|
||||
meta_error_trap_push_with_return (display);
|
||||
meta_error_trap_push (display);
|
||||
|
||||
/* We need to or with the existing event mask since
|
||||
* gtk+ may be interested in other events.
|
||||
@ -674,8 +678,9 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->xscreen = ScreenOfDisplay (xdisplay, number);
|
||||
screen->xroot = xroot;
|
||||
screen->rect.x = screen->rect.y = 0;
|
||||
|
||||
meta_monitor_manager_initialize ();
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
meta_monitor_manager_initialize ();
|
||||
|
||||
manager = meta_monitor_manager_get ();
|
||||
g_signal_connect (manager, "monitors-changed",
|
||||
@ -688,7 +693,6 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->current_cursor = -1; /* invalid/unset */
|
||||
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
|
||||
screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
|
||||
screen->flash_window = None;
|
||||
|
||||
screen->wm_sn_selection_window = new_wm_sn_owner;
|
||||
screen->wm_sn_atom = wm_sn_atom;
|
||||
@ -706,7 +710,6 @@ meta_screen_new (MetaDisplay *display,
|
||||
screen->columns_of_workspaces = -1;
|
||||
screen->vertical_workspaces = FALSE;
|
||||
screen->starting_corner = META_SCREEN_TOPLEFT;
|
||||
screen->compositor_data = NULL;
|
||||
screen->guard_window = None;
|
||||
|
||||
reload_monitor_infos (screen);
|
||||
@ -807,11 +810,7 @@ meta_screen_free (MetaScreen *screen,
|
||||
|
||||
meta_display_grab (display);
|
||||
|
||||
if (screen->display->compositor)
|
||||
{
|
||||
meta_compositor_unmanage_screen (screen->display->compositor,
|
||||
screen);
|
||||
}
|
||||
meta_compositor_unmanage (screen->display->compositor);
|
||||
|
||||
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
|
||||
|
||||
@ -842,10 +841,10 @@ meta_screen_free (MetaScreen *screen,
|
||||
meta_stack_free (screen->stack);
|
||||
meta_stack_tracker_free (screen->stack_tracker);
|
||||
|
||||
meta_error_trap_push_with_return (screen->display);
|
||||
meta_error_trap_push (screen->display);
|
||||
XSelectInput (screen->display->xdisplay, screen->xroot, 0);
|
||||
if (meta_error_trap_pop_with_return (screen->display) != Success)
|
||||
meta_warning (_("Could not release screen %d on display \"%s\"\n"),
|
||||
meta_warning ("Could not release screen %d on display \"%s\"\n",
|
||||
screen->number, screen->display->name);
|
||||
|
||||
unset_wm_check_hint (screen);
|
||||
@ -872,55 +871,36 @@ meta_screen_free (MetaScreen *screen,
|
||||
meta_display_ungrab (display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_create_guard_window (MetaScreen *screen)
|
||||
{
|
||||
if (screen->guard_window == None)
|
||||
screen->guard_window = create_guard_window (screen->display->xdisplay, screen);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_manage_all_windows (MetaScreen *screen)
|
||||
{
|
||||
Window *_children;
|
||||
Window *children;
|
||||
MetaStackWindow *_children;
|
||||
MetaStackWindow *children;
|
||||
int n_children, i;
|
||||
|
||||
if (screen->guard_window == None)
|
||||
screen->guard_window = create_guard_window (screen->display->xdisplay,
|
||||
screen);
|
||||
|
||||
meta_stack_freeze (screen->stack);
|
||||
meta_stack_tracker_get_stack (screen->stack_tracker, &_children, &n_children);
|
||||
|
||||
/* Copy the stack as it will be modified as part of the loop */
|
||||
children = g_memdup (_children, sizeof (Window) * n_children);
|
||||
children = g_memdup (_children, sizeof (MetaStackWindow) * n_children);
|
||||
|
||||
for (i = 0; i < n_children; ++i)
|
||||
{
|
||||
meta_window_new (screen->display, children[i], TRUE,
|
||||
META_COMP_EFFECT_NONE);
|
||||
meta_window_x11_new (screen->display, children[i].x11.xwindow, TRUE,
|
||||
META_COMP_EFFECT_NONE);
|
||||
}
|
||||
|
||||
g_free (children);
|
||||
meta_stack_thaw (screen->stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_screen_for_x_screen:
|
||||
* @xscreen: an X screen structure.
|
||||
*
|
||||
* Gets the #MetaScreen corresponding to an X screen structure.
|
||||
*
|
||||
* Return value: (transfer none): the #MetaScreen for the X screen
|
||||
* %NULL if Metacity is not managing the screen.
|
||||
*/
|
||||
MetaScreen*
|
||||
meta_screen_for_x_screen (Screen *xscreen)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
display = meta_display_for_x_display (DisplayOfScreen (xscreen));
|
||||
|
||||
if (display == NULL)
|
||||
return NULL;
|
||||
|
||||
return meta_display_screen_for_x_screen (display, xscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
prefs_changed_callback (MetaPreference pref,
|
||||
gpointer data)
|
||||
@ -1404,6 +1384,26 @@ update_focus_mode (MetaScreen *screen)
|
||||
/* nothing to do anymore */ ;
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_update_cursor (MetaScreen *screen)
|
||||
{
|
||||
MetaDisplay *display = screen->display;
|
||||
MetaCursor cursor = screen->current_cursor;
|
||||
Cursor xcursor;
|
||||
MetaCursorReference *cursor_ref;
|
||||
|
||||
cursor_ref = meta_cursor_reference_from_theme (screen->cursor_tracker, cursor);
|
||||
meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor_ref);
|
||||
meta_cursor_reference_unref (cursor_ref);
|
||||
|
||||
/* Set a cursor for X11 applications that don't specify their own */
|
||||
xcursor = meta_display_create_x_cursor (display, cursor);
|
||||
|
||||
XDefineCursor (display->xdisplay, screen->xroot, xcursor);
|
||||
XFlush (display->xdisplay);
|
||||
XFreeCursor (display->xdisplay, xcursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_set_cursor (MetaScreen *screen,
|
||||
MetaCursor cursor)
|
||||
@ -1412,14 +1412,7 @@ meta_screen_set_cursor (MetaScreen *screen,
|
||||
return;
|
||||
|
||||
screen->current_cursor = cursor;
|
||||
meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_update_cursor (MetaScreen *screen)
|
||||
{
|
||||
meta_cursor_tracker_set_root_cursor (screen->cursor_tracker,
|
||||
screen->current_cursor);
|
||||
meta_screen_update_cursor (screen);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -1460,11 +1453,10 @@ meta_screen_update_tile_preview_timeout (gpointer data)
|
||||
monitor = meta_window_get_current_tile_monitor_number (window);
|
||||
meta_window_get_current_tile_area (window, &tile_rect);
|
||||
meta_compositor_show_tile_preview (screen->display->compositor,
|
||||
screen, window, &tile_rect, monitor);
|
||||
window, &tile_rect, monitor);
|
||||
}
|
||||
else
|
||||
meta_compositor_hide_tile_preview (screen->display->compositor,
|
||||
screen);
|
||||
meta_compositor_hide_tile_preview (screen->display->compositor);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1500,8 +1492,7 @@ meta_screen_hide_tile_preview (MetaScreen *screen)
|
||||
if (screen->tile_preview_timeout_id > 0)
|
||||
g_source_remove (screen->tile_preview_timeout_id);
|
||||
|
||||
meta_compositor_hide_tile_preview (screen->display->compositor,
|
||||
screen);
|
||||
meta_compositor_hide_tile_preview (screen->display->compositor);
|
||||
}
|
||||
|
||||
MetaWindow*
|
||||
@ -1509,38 +1500,19 @@ meta_screen_get_mouse_window (MetaScreen *screen,
|
||||
MetaWindow *not_this_one)
|
||||
{
|
||||
MetaWindow *window;
|
||||
Window root_return, child_return;
|
||||
double root_x_return, root_y_return;
|
||||
double win_x_return, win_y_return;
|
||||
XIButtonState buttons;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
int x, y;
|
||||
|
||||
if (not_this_one)
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing mouse window excluding %s\n", not_this_one->desc);
|
||||
|
||||
meta_error_trap_push (screen->display);
|
||||
XIQueryPointer (screen->display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
screen->xroot,
|
||||
&root_return,
|
||||
&child_return,
|
||||
&root_x_return,
|
||||
&root_y_return,
|
||||
&win_x_return,
|
||||
&win_y_return,
|
||||
&buttons,
|
||||
&mods,
|
||||
&group);
|
||||
meta_error_trap_pop (screen->display);
|
||||
free (buttons.mask);
|
||||
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
|
||||
&x, &y, NULL);
|
||||
|
||||
window = meta_stack_get_default_focus_window_at_point (screen->stack,
|
||||
screen->active_workspace,
|
||||
not_this_one,
|
||||
root_x_return,
|
||||
root_y_return);
|
||||
x, y);
|
||||
|
||||
return window;
|
||||
}
|
||||
@ -1822,28 +1794,11 @@ meta_screen_get_current_monitor (MetaScreen *screen)
|
||||
|
||||
if (screen->display->monitor_cache_invalidated)
|
||||
{
|
||||
Window root_return, child_return;
|
||||
double win_x_return, win_y_return;
|
||||
double root_x_return, root_y_return;
|
||||
XIButtonState buttons;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
int x, y;
|
||||
|
||||
XIQueryPointer (screen->display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
screen->xroot,
|
||||
&root_return,
|
||||
&child_return,
|
||||
&root_x_return,
|
||||
&root_y_return,
|
||||
&win_x_return,
|
||||
&win_y_return,
|
||||
&buttons,
|
||||
&mods,
|
||||
&group);
|
||||
free (buttons.mask);
|
||||
|
||||
meta_screen_get_current_monitor_for_pos (screen, root_x_return, root_y_return);
|
||||
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
|
||||
&x, &y, NULL);
|
||||
meta_screen_get_current_monitor_for_pos (screen, x, y);
|
||||
}
|
||||
|
||||
return screen->last_monitor_index;
|
||||
@ -2554,10 +2509,8 @@ on_monitors_changed (MetaMonitorManager *manager,
|
||||
&changes);
|
||||
}
|
||||
|
||||
if (screen->display->compositor)
|
||||
meta_compositor_sync_screen_size (screen->display->compositor,
|
||||
screen,
|
||||
screen->rect.width, screen->rect.height);
|
||||
meta_compositor_sync_screen_size (screen->display->compositor,
|
||||
screen->rect.width, screen->rect.height);
|
||||
|
||||
/* Queue a resize on all the windows */
|
||||
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
|
||||
@ -3097,24 +3050,6 @@ meta_screen_get_size (MetaScreen *screen,
|
||||
*height = screen->rect.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_screen_get_compositor_data: (skip)
|
||||
* @screen: A #MetaScreen
|
||||
*
|
||||
*/
|
||||
gpointer
|
||||
meta_screen_get_compositor_data (MetaScreen *screen)
|
||||
{
|
||||
return screen->compositor_data;
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_set_compositor_data (MetaScreen *screen,
|
||||
gpointer compositor)
|
||||
{
|
||||
screen->compositor_data = compositor;
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_set_cm_selection (MetaScreen *screen)
|
||||
{
|
||||
@ -3373,10 +3308,6 @@ gboolean
|
||||
meta_screen_handle_xevent (MetaScreen *screen,
|
||||
XEvent *xevent)
|
||||
{
|
||||
/* Go through our helpers and see if they want this event.
|
||||
Currently, only MetaCursorTracker.
|
||||
*/
|
||||
|
||||
if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent))
|
||||
return TRUE;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -35,36 +35,55 @@
|
||||
#define META_STACK_TRACKER_H
|
||||
|
||||
#include <meta/screen.h>
|
||||
#include <meta/window.h>
|
||||
|
||||
typedef struct _MetaStackTracker MetaStackTracker;
|
||||
|
||||
typedef union _MetaStackWindow
|
||||
{
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
} any;
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
Window xwindow;
|
||||
} x11;
|
||||
struct {
|
||||
MetaWindowClientType type;
|
||||
MetaWindow *meta_window;
|
||||
} wayland;
|
||||
} MetaStackWindow;
|
||||
|
||||
gboolean meta_stack_window_equal (const MetaStackWindow *a,
|
||||
const MetaStackWindow *b);
|
||||
|
||||
MetaStackTracker *meta_stack_tracker_new (MetaScreen *screen);
|
||||
void meta_stack_tracker_free (MetaStackTracker *tracker);
|
||||
|
||||
/* These functions are called when we make an X call that changes the
|
||||
* stacking order; this allows MetaStackTracker to predict stacking
|
||||
* order before it receives events back from the X server */
|
||||
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
|
||||
Window *windows,
|
||||
int n_windows,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
Window sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
Window sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
|
||||
Window window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_add (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_remove (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_restack_windows (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *windows,
|
||||
int n_windows,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
const MetaStackWindow *sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower_below (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
const MetaStackWindow *sibling,
|
||||
gulong serial);
|
||||
void meta_stack_tracker_record_lower (MetaStackTracker *tracker,
|
||||
const MetaStackWindow *window,
|
||||
gulong serial);
|
||||
|
||||
/* These functions are used to update the stack when we get events
|
||||
* reflecting changes to the stacking order */
|
||||
@ -77,9 +96,9 @@ void meta_stack_tracker_reparent_event (MetaStackTracker *tracker,
|
||||
void meta_stack_tracker_configure_event (MetaStackTracker *tracker,
|
||||
XConfigureEvent *event);
|
||||
|
||||
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
|
||||
Window **windows,
|
||||
int *n_windows);
|
||||
void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
|
||||
MetaStackWindow **windows,
|
||||
int *n_entries);
|
||||
|
||||
void meta_stack_tracker_sync_stack (MetaStackTracker *tracker);
|
||||
void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);
|
||||
|
593
src/core/stack.c
593
src/core/stack.c
@ -36,6 +36,8 @@
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "x11/group-private.h"
|
||||
|
||||
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
|
||||
(w->type == META_WINDOW_DIALOG || \
|
||||
w->type == META_WINDOW_MODAL_DIALOG || \
|
||||
@ -50,7 +52,7 @@
|
||||
|
||||
#define WINDOW_IN_STACK(w) (w->stack_position >= 0)
|
||||
|
||||
static void stack_sync_to_server (MetaStack *stack);
|
||||
static void stack_sync_to_xserver (MetaStack *stack);
|
||||
static void meta_window_set_stack_position_no_sync (MetaWindow *window,
|
||||
int position);
|
||||
static void stack_do_window_deletions (MetaStack *stack);
|
||||
@ -69,14 +71,14 @@ meta_stack_new (MetaScreen *screen)
|
||||
stack = g_new (MetaStack, 1);
|
||||
|
||||
stack->screen = screen;
|
||||
stack->windows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
stack->sorted = NULL;
|
||||
stack->added = NULL;
|
||||
stack->removed = NULL;
|
||||
|
||||
stack->freeze_count = 0;
|
||||
stack->last_root_children_stacked = NULL;
|
||||
stack->last_all_root_children_stacked = NULL;
|
||||
|
||||
stack->n_positions = 0;
|
||||
|
||||
@ -87,17 +89,24 @@ meta_stack_new (MetaScreen *screen)
|
||||
return stack;
|
||||
}
|
||||
|
||||
static void
|
||||
free_last_all_root_children_stacked_cache (MetaStack *stack)
|
||||
{
|
||||
g_array_free (stack->last_all_root_children_stacked, TRUE);
|
||||
stack->last_all_root_children_stacked = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_stack_free (MetaStack *stack)
|
||||
{
|
||||
g_array_free (stack->windows, TRUE);
|
||||
g_array_free (stack->xwindows, TRUE);
|
||||
|
||||
g_list_free (stack->sorted);
|
||||
g_list_free (stack->added);
|
||||
g_list_free (stack->removed);
|
||||
|
||||
if (stack->last_root_children_stacked)
|
||||
g_array_free (stack->last_root_children_stacked, TRUE);
|
||||
if (stack->last_all_root_children_stacked)
|
||||
free_last_all_root_children_stacked_cache (stack);
|
||||
|
||||
g_free (stack);
|
||||
}
|
||||
@ -119,7 +128,7 @@ meta_stack_add (MetaStack *stack,
|
||||
"Window %s has stack_position initialized to %d\n",
|
||||
window->desc, window->stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -155,7 +164,7 @@ meta_stack_remove (MetaStack *stack,
|
||||
stack->removed = g_list_prepend (stack->removed,
|
||||
GUINT_TO_POINTER (window->frame->xwindow));
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -165,7 +174,7 @@ meta_stack_update_layer (MetaStack *stack,
|
||||
{
|
||||
stack->need_relayer = TRUE;
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -175,7 +184,7 @@ meta_stack_update_transient (MetaStack *stack,
|
||||
{
|
||||
stack->need_constrain = TRUE;
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -204,7 +213,7 @@ meta_stack_raise (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, max_stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -232,7 +241,7 @@ meta_stack_lower (MetaStack *stack,
|
||||
|
||||
meta_window_set_stack_position_no_sync (window, min_stack_position);
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, window->screen->active_workspace);
|
||||
}
|
||||
|
||||
@ -248,7 +257,7 @@ meta_stack_thaw (MetaStack *stack)
|
||||
g_return_if_fail (stack->freeze_count > 0);
|
||||
|
||||
stack->freeze_count -= 1;
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@ -827,7 +836,7 @@ stack_do_window_deletions (MetaStack *stack)
|
||||
/* We go from the end figuring removals are more
|
||||
* likely to be recent.
|
||||
*/
|
||||
i = stack->windows->len;
|
||||
i = stack->xwindows->len;
|
||||
while (i > 0)
|
||||
{
|
||||
--i;
|
||||
@ -838,9 +847,9 @@ stack_do_window_deletions (MetaStack *stack)
|
||||
* both the window->xwindow and window->frame->xwindow
|
||||
* in the removal list.
|
||||
*/
|
||||
if (xwindow == g_array_index (stack->windows, Window, i))
|
||||
if (xwindow == g_array_index (stack->xwindows, Window, i))
|
||||
{
|
||||
g_array_remove_index (stack->windows, i);
|
||||
g_array_remove_index (stack->xwindows, i);
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
@ -869,10 +878,10 @@ stack_do_window_additions (MetaStack *stack)
|
||||
"Adding %d windows to sorted list\n",
|
||||
n_added);
|
||||
|
||||
old_size = stack->windows->len;
|
||||
g_array_set_size (stack->windows, old_size + n_added);
|
||||
old_size = stack->xwindows->len;
|
||||
g_array_set_size (stack->xwindows, old_size + n_added);
|
||||
|
||||
end = &g_array_index (stack->windows, Window, old_size);
|
||||
end = &g_array_index (stack->xwindows, Window, old_size);
|
||||
|
||||
/* stack->added has the most recent additions at the
|
||||
* front of the list, so we need to reverse it
|
||||
@ -1027,6 +1036,102 @@ stack_ensure_sorted (MetaStack *stack)
|
||||
stack_do_resort (stack);
|
||||
}
|
||||
|
||||
static MetaStackWindow *
|
||||
find_top_most_managed_window (MetaScreen *screen,
|
||||
const MetaStackWindow *ignore)
|
||||
{
|
||||
MetaStackTracker *stack_tracker = screen->stack_tracker;
|
||||
MetaStackWindow *windows;
|
||||
int n_windows;
|
||||
int i;
|
||||
|
||||
meta_stack_tracker_get_stack (stack_tracker,
|
||||
&windows, &n_windows);
|
||||
|
||||
/* Children are in order from bottom to top. We want to
|
||||
* find the topmost managed child, then configure
|
||||
* our window to be above it.
|
||||
*/
|
||||
for (i = n_windows -1; i >= 0; i--)
|
||||
{
|
||||
MetaStackWindow *other_window = &windows[i];
|
||||
|
||||
if (other_window->any.type == ignore->any.type &&
|
||||
((other_window->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
other_window->x11.xwindow == ignore->x11.xwindow) ||
|
||||
other_window->wayland.meta_window == ignore->wayland.meta_window))
|
||||
{
|
||||
/* Do nothing. This means we're already the topmost managed
|
||||
* window, but it DOES NOT mean we are already just above
|
||||
* the topmost managed window. This is important because if
|
||||
* an override redirect window is up, and we map a new
|
||||
* managed window, the new window is probably above the old
|
||||
* popup by default, and we want to push it below that
|
||||
* popup. So keep looking for a sibling managed window
|
||||
* to be moved below.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (other_window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
MetaWindow *other = meta_display_lookup_x_window (screen->display,
|
||||
other_window->x11.xwindow);
|
||||
|
||||
if (other != NULL && !other->override_redirect)
|
||||
return other_window;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* All wayland windows are currently considered "managed"
|
||||
* TODO: consider wayland pop-up windows like override
|
||||
* redirect windows here. */
|
||||
return other_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* When moving an X window we sometimes need an X based sibling.
|
||||
*
|
||||
* If the given sibling is X based this function returns it back
|
||||
* otherwise it searches downwards looking for the nearest X window.
|
||||
*
|
||||
* If no X based sibling could be found return NULL. */
|
||||
static MetaStackWindow *
|
||||
find_x11_sibling_downwards (MetaScreen *screen,
|
||||
MetaStackWindow *sibling)
|
||||
{
|
||||
MetaStackTracker *stack_tracker = screen->stack_tracker;
|
||||
MetaStackWindow *windows;
|
||||
int n_windows;
|
||||
int i;
|
||||
|
||||
if (sibling->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
return sibling;
|
||||
|
||||
meta_stack_tracker_get_stack (stack_tracker,
|
||||
&windows, &n_windows);
|
||||
|
||||
/* NB: Children are in order from bottom to top and we
|
||||
* want to search downwards for the nearest X window.
|
||||
*/
|
||||
|
||||
for (i = n_windows - 1; i >= 0; i--)
|
||||
if (meta_stack_window_equal (&windows[i], sibling))
|
||||
break;
|
||||
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
if (windows[i].any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
return &windows[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* raise_window_relative_to_managed_windows:
|
||||
*
|
||||
@ -1051,84 +1156,74 @@ stack_ensure_sorted (MetaStack *stack)
|
||||
*/
|
||||
static void
|
||||
raise_window_relative_to_managed_windows (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
const MetaStackWindow *window)
|
||||
{
|
||||
gulong serial = 0;
|
||||
MetaStackWindow *sibling;
|
||||
|
||||
Window *children;
|
||||
int n_children;
|
||||
int i;
|
||||
|
||||
meta_stack_tracker_get_stack (screen->stack_tracker,
|
||||
&children, &n_children);
|
||||
|
||||
/* Children are in order from bottom to top. We want to
|
||||
* find the topmost managed child, then configure
|
||||
* our window to be above it.
|
||||
*/
|
||||
i = n_children - 1;
|
||||
while (i >= 0)
|
||||
sibling = find_top_most_managed_window (screen, window);
|
||||
if (!sibling)
|
||||
{
|
||||
if (children[i] == xwindow)
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
/* Do nothing. This means we're already the topmost managed
|
||||
* window, but it DOES NOT mean we are already just above
|
||||
* the topmost managed window. This is important because if
|
||||
* an override redirect window is up, and we map a new
|
||||
* managed window, the new window is probably above the old
|
||||
* popup by default, and we want to push it below that
|
||||
* popup. So keep looking for a sibling managed window
|
||||
* to be moved below.
|
||||
*/
|
||||
serial = XNextRequest (screen->display->xdisplay);
|
||||
meta_error_trap_push (screen->display);
|
||||
XLowerWindow (screen->display->xdisplay,
|
||||
window->x11.xwindow);
|
||||
meta_error_trap_pop (screen->display);
|
||||
}
|
||||
else
|
||||
{
|
||||
MetaWindow *other = meta_display_lookup_x_window (screen->display,
|
||||
children[i]);
|
||||
if (other != NULL && !other->override_redirect)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
|
||||
/* children[i] is the topmost managed child */
|
||||
/* No sibling to use, just lower ourselves to the bottom
|
||||
* to be sure we're below any override redirect windows.
|
||||
*/
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
window,
|
||||
serial);
|
||||
return;
|
||||
}
|
||||
|
||||
/* window is the topmost managed child */
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Moving 0x%lx above topmost managed child window 0x%lx\n",
|
||||
xwindow, children[i]);
|
||||
window->any.type == META_WINDOW_CLIENT_TYPE_X11 ? window->x11.xwindow: 0,
|
||||
sibling->any.type == META_WINDOW_CLIENT_TYPE_X11 ? sibling->x11.xwindow: 0);
|
||||
|
||||
changes.sibling = children[i];
|
||||
if (window->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
MetaStackWindow *x11_sibling = find_x11_sibling_downwards (screen, sibling);
|
||||
serial = XNextRequest (screen->display->xdisplay);
|
||||
|
||||
if (x11_sibling)
|
||||
{
|
||||
changes.sibling = x11_sibling->x11.xwindow;
|
||||
changes.stack_mode = Above;
|
||||
|
||||
meta_error_trap_push (screen->display);
|
||||
meta_stack_tracker_record_raise_above (screen->stack_tracker,
|
||||
xwindow,
|
||||
children[i],
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
XConfigureWindow (screen->display->xdisplay,
|
||||
xwindow,
|
||||
window->x11.xwindow,
|
||||
CWSibling | CWStackMode,
|
||||
&changes);
|
||||
meta_error_trap_pop (screen->display);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
else
|
||||
{
|
||||
/* No sibling to use, just lower ourselves to the bottom
|
||||
* to be sure we're below any override redirect windows.
|
||||
*/
|
||||
meta_error_trap_push (screen->display);
|
||||
meta_stack_tracker_record_lower (screen->stack_tracker,
|
||||
xwindow,
|
||||
XNextRequest (screen->display->xdisplay));
|
||||
XLowerWindow (screen->display->xdisplay,
|
||||
xwindow);
|
||||
window->x11.xwindow);
|
||||
meta_error_trap_pop (screen->display);
|
||||
}
|
||||
}
|
||||
|
||||
meta_stack_tracker_record_raise_above (screen->stack_tracker,
|
||||
window,
|
||||
sibling,
|
||||
serial);
|
||||
}
|
||||
|
||||
/**
|
||||
* stack_sync_to_server:
|
||||
*
|
||||
@ -1143,13 +1238,16 @@ raise_window_relative_to_managed_windows (MetaScreen *screen,
|
||||
* job of computing the minimal set of stacking requests needed.
|
||||
*/
|
||||
static void
|
||||
stack_sync_to_server (MetaStack *stack)
|
||||
stack_sync_to_xserver (MetaStack *stack)
|
||||
{
|
||||
GArray *stacked;
|
||||
GArray *root_children_stacked;
|
||||
GArray *x11_stacked;
|
||||
GArray *x11_root_children_stacked;
|
||||
GArray *all_root_children_stacked; /* wayland OR x11 */
|
||||
GList *tmp;
|
||||
GArray *all_hidden;
|
||||
GArray *x11_hidden;
|
||||
GArray *x11_hidden_stack_windows;
|
||||
int n_override_redirect = 0;
|
||||
MetaStackWindow guard_stack_window;
|
||||
|
||||
/* Bail out if frozen */
|
||||
if (stack->freeze_count > 0)
|
||||
@ -1164,13 +1262,17 @@ stack_sync_to_server (MetaStack *stack)
|
||||
* _NET hints, and "root_children_stacked" is in top-to-bottom
|
||||
* order for XRestackWindows()
|
||||
*/
|
||||
stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
|
||||
x11_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
x11_hidden_stack_windows = g_array_new (FALSE, FALSE, sizeof (MetaStackWindow));
|
||||
x11_hidden = g_array_new (FALSE, FALSE, sizeof (Window));
|
||||
|
||||
/* The screen guard window sits above all hidden windows and acts as
|
||||
* a barrier to input reaching these windows. */
|
||||
g_array_append_val (all_hidden, stack->screen->guard_window);
|
||||
g_array_append_val (x11_hidden, stack->screen->guard_window);
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Top to bottom: ");
|
||||
meta_push_no_msg_prefix ();
|
||||
@ -1179,6 +1281,9 @@ stack_sync_to_server (MetaStack *stack)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
Window top_level_window;
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
stack_window.any.type = w->client_type;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
|
||||
w->layer, w->stack_position, w->desc);
|
||||
@ -1187,60 +1292,82 @@ stack_sync_to_server (MetaStack *stack)
|
||||
if (w->override_redirect)
|
||||
n_override_redirect++;
|
||||
else
|
||||
g_array_prepend_val (stacked, w->xwindow);
|
||||
g_array_prepend_val (x11_stacked, w->xwindow);
|
||||
|
||||
if (w->frame)
|
||||
top_level_window = w->frame->xwindow;
|
||||
else
|
||||
top_level_window = w->xwindow;
|
||||
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
stack_window.x11.xwindow = top_level_window;
|
||||
else
|
||||
stack_window.wayland.meta_window = w;
|
||||
|
||||
/* We don't restack hidden windows along with the rest, though they are
|
||||
* reflected in the _NET hints. Hidden windows all get pushed below
|
||||
* the screens fullscreen guard_window. */
|
||||
if (w->hidden)
|
||||
{
|
||||
g_array_append_val (all_hidden, top_level_window);
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
MetaStackWindow stack_window;
|
||||
|
||||
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
stack_window.x11.xwindow = top_level_window;
|
||||
|
||||
g_array_append_val (x11_hidden_stack_windows, stack_window);
|
||||
g_array_append_val (x11_hidden, top_level_window);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
g_array_append_val (all_root_children_stacked, stack_window);
|
||||
|
||||
/* build XRestackWindows() array from top to bottom */
|
||||
g_array_append_val (root_children_stacked, top_level_window);
|
||||
if (w->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
g_array_append_val (x11_root_children_stacked, top_level_window);
|
||||
}
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "\n");
|
||||
meta_pop_no_msg_prefix ();
|
||||
|
||||
/* All windows should be in some stacking order */
|
||||
if (stacked->len != stack->windows->len - n_override_redirect)
|
||||
/* All X windows should be in some stacking order */
|
||||
if (x11_stacked->len != stack->xwindows->len - n_override_redirect)
|
||||
meta_bug ("%u windows stacked, %u windows exist in stack\n",
|
||||
stacked->len, stack->windows->len);
|
||||
x11_stacked->len, stack->xwindows->len);
|
||||
|
||||
/* Sync to server */
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
|
||||
root_children_stacked->len);
|
||||
all_root_children_stacked->len);
|
||||
|
||||
meta_error_trap_push (stack->screen->display);
|
||||
|
||||
if (stack->last_root_children_stacked == NULL)
|
||||
if (stack->last_all_root_children_stacked == NULL)
|
||||
{
|
||||
/* Just impose our stack, we don't know the previous state.
|
||||
* This involves a ton of circulate requests and may flicker.
|
||||
*/
|
||||
meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");
|
||||
|
||||
if (root_children_stacked->len > 0)
|
||||
if (all_root_children_stacked->len > 1)
|
||||
{
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *) root_children_stacked->data,
|
||||
root_children_stacked->len,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
gulong serial = 0;
|
||||
if (x11_root_children_stacked->len > 1)
|
||||
{
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *) root_children_stacked->data,
|
||||
root_children_stacked->len);
|
||||
(Window *) x11_root_children_stacked->data,
|
||||
x11_root_children_stacked->len);
|
||||
}
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(MetaStackWindow *) all_root_children_stacked->data,
|
||||
all_root_children_stacked->len,
|
||||
serial);
|
||||
}
|
||||
}
|
||||
else if (root_children_stacked->len > 0)
|
||||
else if (all_root_children_stacked->len > 0)
|
||||
{
|
||||
/* Try to do minimal window moves to get the stack in order */
|
||||
/* A point of note: these arrays include frames not client windows,
|
||||
@ -1248,28 +1375,34 @@ stack_sync_to_server (MetaStack *stack)
|
||||
* was saved, then we may have inefficiency, but I don't think things
|
||||
* break...
|
||||
*/
|
||||
const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
|
||||
const Window *new_stack = (Window *) root_children_stacked->data;
|
||||
const int old_len = stack->last_root_children_stacked->len;
|
||||
const int new_len = root_children_stacked->len;
|
||||
const Window *oldp = old_stack;
|
||||
const Window *newp = new_stack;
|
||||
const Window *old_end = old_stack + old_len;
|
||||
const Window *new_end = new_stack + new_len;
|
||||
Window last_window = None;
|
||||
|
||||
const MetaStackWindow *old_stack = (MetaStackWindow *) stack->last_all_root_children_stacked->data;
|
||||
const MetaStackWindow *new_stack = (MetaStackWindow *) all_root_children_stacked->data;
|
||||
const int old_len = stack->last_all_root_children_stacked->len;
|
||||
const int new_len = all_root_children_stacked->len;
|
||||
const MetaStackWindow *oldp = old_stack;
|
||||
const MetaStackWindow *newp = new_stack;
|
||||
const MetaStackWindow *old_end = old_stack + old_len;
|
||||
const MetaStackWindow *new_end = new_stack + new_len;
|
||||
Window last_xwindow = None;
|
||||
const MetaStackWindow *last_window = NULL;
|
||||
|
||||
while (oldp != old_end &&
|
||||
newp != new_end)
|
||||
{
|
||||
if (*oldp == *newp)
|
||||
if (meta_stack_window_equal (oldp, newp))
|
||||
{
|
||||
/* Stacks are the same here, move on */
|
||||
++oldp;
|
||||
last_window = *newp;
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
last_xwindow = newp->x11.xwindow;
|
||||
last_window = newp;
|
||||
++newp;
|
||||
}
|
||||
else if (meta_display_lookup_x_window (stack->screen->display,
|
||||
*oldp) == NULL)
|
||||
else if ((oldp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
meta_display_lookup_x_window (stack->screen->display,
|
||||
oldp->x11.xwindow) == NULL) ||
|
||||
(oldp->any.type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
|
||||
oldp->wayland.meta_window == NULL))
|
||||
{
|
||||
/* *oldp is no longer known to us (probably destroyed),
|
||||
* so we can just skip it
|
||||
@ -1278,75 +1411,161 @@ stack_sync_to_server (MetaStack *stack)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move *newp below last_window */
|
||||
if (last_window == None)
|
||||
/* Move *newp below the last_window */
|
||||
if (!last_window)
|
||||
{
|
||||
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);
|
||||
meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n",
|
||||
newp->x11.xwindow);
|
||||
|
||||
raise_window_relative_to_managed_windows (stack->screen,
|
||||
*newp);
|
||||
raise_window_relative_to_managed_windows (stack->screen, newp);
|
||||
}
|
||||
else if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11 &&
|
||||
last_xwindow == None)
|
||||
{
|
||||
/* In this case we have an X window that we need to
|
||||
* put below a wayland window and this is the
|
||||
* topmost X window. */
|
||||
|
||||
/* In X terms (because this is the topmost X window)
|
||||
* we want to
|
||||
* raise_window_relative_to_managed_windows() to
|
||||
* ensure the X window is below override-redirect
|
||||
* pop-up windows.
|
||||
*
|
||||
* In Wayland terms we just want to ensure
|
||||
* newp is lowered below last_window (which
|
||||
* notably doesn't require an X request because we
|
||||
* know last_window isn't an X window).
|
||||
*/
|
||||
|
||||
raise_window_relative_to_managed_windows (stack->screen, newp);
|
||||
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
newp, last_window,
|
||||
0); /* no x request serial */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This means that if last_window is dead, but not
|
||||
gulong serial = 0;
|
||||
|
||||
/* This means that if last_xwindow is dead, but not
|
||||
* *newp, then we fail to restack *newp; but on
|
||||
* unmanaging last_window, we'll fix it up.
|
||||
* unmanaging last_xwindow, we'll fix it up.
|
||||
*/
|
||||
|
||||
XWindowChanges changes;
|
||||
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
|
||||
newp->any.type == META_WINDOW_CLIENT_TYPE_X11 ? newp->x11.xwindow : 0,
|
||||
last_xwindow);
|
||||
|
||||
changes.sibling = last_window;
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
|
||||
changes.sibling = last_xwindow;
|
||||
changes.stack_mode = Below;
|
||||
|
||||
meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
|
||||
*newp, last_window);
|
||||
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
*newp, last_window,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XConfigureWindow (stack->screen->display->xdisplay,
|
||||
*newp,
|
||||
newp->x11.xwindow,
|
||||
CWSibling | CWStackMode,
|
||||
&changes);
|
||||
}
|
||||
|
||||
last_window = *newp;
|
||||
meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
|
||||
newp, last_window,
|
||||
serial);
|
||||
}
|
||||
|
||||
if (newp->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
last_xwindow = newp->x11.xwindow;
|
||||
last_window = newp;
|
||||
++newp;
|
||||
}
|
||||
}
|
||||
|
||||
if (newp != new_end)
|
||||
{
|
||||
const MetaStackWindow *x_ref;
|
||||
unsigned long serial = 0;
|
||||
|
||||
/* Restack remaining windows */
|
||||
meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
|
||||
(int) (new_end - newp));
|
||||
|
||||
/* rewind until we find the last stacked X window that we can use
|
||||
* as a reference point for re-stacking remaining X windows */
|
||||
if (newp != new_stack)
|
||||
for (x_ref = newp - 1;
|
||||
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
|
||||
x_ref--)
|
||||
;
|
||||
else
|
||||
x_ref = new_stack;
|
||||
|
||||
/* If we didn't find an X window looking backwards then walk forwards
|
||||
* through the remaining windows to find the first remaining X window
|
||||
* instead. */
|
||||
if (x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
for (x_ref = newp;
|
||||
x_ref->any.type != META_WINDOW_CLIENT_TYPE_X11 && x_ref > new_stack;
|
||||
x_ref++)
|
||||
;
|
||||
}
|
||||
|
||||
/* If there are any X windows remaining unstacked then restack them */
|
||||
if (x_ref->any.type == META_WINDOW_CLIENT_TYPE_X11)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = x11_root_children_stacked->len - 1; i; i--)
|
||||
{
|
||||
Window *reference = &g_array_index (x11_root_children_stacked, Window, i);
|
||||
|
||||
if (*reference == x_ref->x11.xwindow)
|
||||
{
|
||||
int n = x11_root_children_stacked->len - i;
|
||||
|
||||
/* There's no point restacking if there's only one X window */
|
||||
if (n == 1)
|
||||
break;
|
||||
|
||||
serial = XNextRequest (stack->screen->display->xdisplay);
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
reference, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to include an already-stacked window
|
||||
* in the restack call, so we get in the proper position
|
||||
* with respect to it.
|
||||
*/
|
||||
if (newp != new_stack)
|
||||
--newp;
|
||||
newp = MIN (newp - 1, x_ref);
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *) newp, new_end - newp,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *) newp, new_end - newp);
|
||||
newp, new_end - newp,
|
||||
serial);
|
||||
}
|
||||
}
|
||||
|
||||
/* Push hidden windows to the bottom of the stack under the guard window */
|
||||
/* Push hidden X windows to the bottom of the stack under the guard window */
|
||||
guard_stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
|
||||
guard_stack_window.x11.xwindow = stack->screen->guard_window;
|
||||
meta_stack_tracker_record_lower (stack->screen->stack_tracker,
|
||||
stack->screen->guard_window,
|
||||
&guard_stack_window,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
|
||||
meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
|
||||
(Window *)all_hidden->data,
|
||||
all_hidden->len,
|
||||
(MetaStackWindow *)x11_hidden_stack_windows->data,
|
||||
x11_hidden_stack_windows->len,
|
||||
XNextRequest (stack->screen->display->xdisplay));
|
||||
XRestackWindows (stack->screen->display->xdisplay,
|
||||
(Window *)all_hidden->data,
|
||||
all_hidden->len);
|
||||
g_array_free (all_hidden, TRUE);
|
||||
(Window *)x11_hidden->data,
|
||||
x11_hidden->len);
|
||||
g_array_free (x11_hidden, TRUE);
|
||||
g_array_free (x11_hidden_stack_windows, TRUE);
|
||||
|
||||
meta_error_trap_pop (stack->screen->display);
|
||||
/* on error, a window was destroyed; it should eventually
|
||||
@ -1361,21 +1580,23 @@ stack_sync_to_server (MetaStack *stack)
|
||||
stack->screen->display->atom__NET_CLIENT_LIST,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stack->windows->data,
|
||||
stack->windows->len);
|
||||
(unsigned char *)stack->xwindows->data,
|
||||
stack->xwindows->len);
|
||||
XChangeProperty (stack->screen->display->xdisplay,
|
||||
stack->screen->xroot,
|
||||
stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
|
||||
XA_WINDOW,
|
||||
32, PropModeReplace,
|
||||
(unsigned char *)stacked->data,
|
||||
stacked->len);
|
||||
(unsigned char *)x11_stacked->data,
|
||||
x11_stacked->len);
|
||||
|
||||
g_array_free (stacked, TRUE);
|
||||
g_array_free (x11_stacked, TRUE);
|
||||
|
||||
if (stack->last_root_children_stacked)
|
||||
g_array_free (stack->last_root_children_stacked, TRUE);
|
||||
stack->last_root_children_stacked = root_children_stacked;
|
||||
if (stack->last_all_root_children_stacked)
|
||||
free_last_all_root_children_stacked_cache (stack);
|
||||
stack->last_all_root_children_stacked = all_root_children_stacked;
|
||||
|
||||
g_array_free (x11_root_children_stacked, TRUE);
|
||||
|
||||
/* That was scary... */
|
||||
}
|
||||
@ -1486,8 +1707,8 @@ get_default_focus_window (MetaStack *stack,
|
||||
MetaWindow *topmost_in_group;
|
||||
MetaWindow *topmost_overall;
|
||||
MetaGroup *not_this_one_group;
|
||||
GList *link;
|
||||
|
||||
GList *l;
|
||||
|
||||
transient_parent = NULL;
|
||||
topmost_in_group = NULL;
|
||||
topmost_overall = NULL;
|
||||
@ -1499,49 +1720,49 @@ get_default_focus_window (MetaStack *stack,
|
||||
stack_ensure_sorted (stack);
|
||||
|
||||
/* top of this layer is at the front of the list */
|
||||
link = stack->sorted;
|
||||
|
||||
while (link)
|
||||
for (l = stack->sorted; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWindow *window = link->data;
|
||||
MetaWindow *window = l->data;
|
||||
|
||||
if (window &&
|
||||
window != not_this_one &&
|
||||
(window->unmaps_pending == 0) &&
|
||||
!window->minimized &&
|
||||
(window->input || window->take_focus) &&
|
||||
(workspace == NULL ||
|
||||
meta_window_located_on_workspace (window, workspace)))
|
||||
if (!window)
|
||||
continue;
|
||||
|
||||
if (window == not_this_one)
|
||||
continue;
|
||||
|
||||
if (window->unmaps_pending > 0)
|
||||
continue;
|
||||
|
||||
if (window->minimized)
|
||||
continue;
|
||||
|
||||
if (!(window->input || window->take_focus))
|
||||
continue;
|
||||
|
||||
if (workspace != NULL && !meta_window_located_on_workspace (window, workspace))
|
||||
continue;
|
||||
|
||||
if (must_be_at_point && !window_contains_point (window, root_x, root_y))
|
||||
continue;
|
||||
|
||||
if (not_this_one != NULL)
|
||||
{
|
||||
if (not_this_one != NULL)
|
||||
{
|
||||
if (transient_parent == NULL &&
|
||||
not_this_one->xtransient_for != None &&
|
||||
not_this_one->xtransient_for == window->xwindow &&
|
||||
(!must_be_at_point ||
|
||||
window_contains_point (window, root_x, root_y)))
|
||||
transient_parent = window;
|
||||
if (transient_parent == NULL &&
|
||||
meta_window_get_transient_for (not_this_one) == window)
|
||||
transient_parent = window;
|
||||
|
||||
if (topmost_in_group == NULL &&
|
||||
not_this_one_group != NULL &&
|
||||
not_this_one_group == meta_window_get_group (window) &&
|
||||
(!must_be_at_point ||
|
||||
window_contains_point (window, root_x, root_y)))
|
||||
topmost_in_group = window;
|
||||
}
|
||||
|
||||
if (topmost_overall == NULL &&
|
||||
window->type != META_WINDOW_DOCK &&
|
||||
(!must_be_at_point ||
|
||||
window_contains_point (window, root_x, root_y)))
|
||||
topmost_overall = window;
|
||||
|
||||
/* We could try to bail out early here for efficiency in
|
||||
* some cases, but it's just not worth the code.
|
||||
*/
|
||||
if (topmost_in_group == NULL &&
|
||||
not_this_one_group != NULL &&
|
||||
not_this_one_group == meta_window_get_group (window))
|
||||
topmost_in_group = window;
|
||||
}
|
||||
|
||||
link = link->next;
|
||||
if (topmost_overall == NULL && window->type != META_WINDOW_DOCK)
|
||||
topmost_overall = window;
|
||||
|
||||
/* We could try to bail out early here for efficiency in
|
||||
* some cases, but it's just not worth the code.
|
||||
*/
|
||||
}
|
||||
|
||||
if (transient_parent)
|
||||
@ -1726,7 +1947,7 @@ meta_stack_set_positions (MetaStack *stack,
|
||||
meta_topic (META_DEBUG_STACK,
|
||||
"Reset the stack positions of (nearly) all windows\n");
|
||||
|
||||
stack_sync_to_server (stack);
|
||||
stack_sync_to_xserver (stack);
|
||||
meta_stack_update_window_tile_matches (stack, NULL);
|
||||
}
|
||||
|
||||
@ -1789,7 +2010,7 @@ meta_window_set_stack_position (MetaWindow *window,
|
||||
int position)
|
||||
{
|
||||
meta_window_set_stack_position_no_sync (window, position);
|
||||
stack_sync_to_server (window->screen->stack);
|
||||
stack_sync_to_xserver (window->screen->stack);
|
||||
meta_stack_update_window_tile_matches (window->screen->stack,
|
||||
window->screen->active_workspace);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ struct _MetaStack
|
||||
* A sequence of all the Windows (X handles, not MetaWindows) of the windows
|
||||
* we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST.
|
||||
*/
|
||||
GArray *windows;
|
||||
GArray *xwindows;
|
||||
|
||||
/** The MetaWindows of the windows we manage, sorted in order. */
|
||||
GList *sorted;
|
||||
@ -97,7 +97,7 @@ struct _MetaStack
|
||||
* The last-known stack of all windows, bottom to top. We cache it here
|
||||
* so that subsequent times we'll be able to do incremental moves.
|
||||
*/
|
||||
GArray *last_root_children_stacked;
|
||||
GArray *last_all_root_children_stacked;
|
||||
|
||||
/**
|
||||
* Number of stack positions; same as the length of added, but
|
||||
|
@ -32,5 +32,6 @@ void meta_set_verbose (gboolean setting);
|
||||
void meta_set_debugging (gboolean setting);
|
||||
void meta_set_syncing (gboolean setting);
|
||||
void meta_set_replace_current_wm (gboolean setting);
|
||||
void meta_set_is_wayland_compositor (gboolean setting);
|
||||
|
||||
#endif
|
||||
|
@ -53,6 +53,7 @@ static gint verbose_topics = 0;
|
||||
static gboolean is_debugging = FALSE;
|
||||
static gboolean replace_current = FALSE;
|
||||
static int no_prefix = 0;
|
||||
static gboolean is_wayland_compositor = FALSE;
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static FILE* logfile = NULL;
|
||||
@ -79,7 +80,7 @@ ensure_logfile (void)
|
||||
|
||||
if (err != NULL)
|
||||
{
|
||||
meta_warning (_("Failed to open debug log: %s\n"),
|
||||
meta_warning ("Failed to open debug log: %s\n",
|
||||
err->message);
|
||||
g_error_free (err);
|
||||
return;
|
||||
@ -89,13 +90,13 @@ ensure_logfile (void)
|
||||
|
||||
if (logfile == NULL)
|
||||
{
|
||||
meta_warning (_("Failed to fdopen() log file %s: %s\n"),
|
||||
meta_warning ("Failed to fdopen() log file %s: %s\n",
|
||||
filename, strerror (errno));
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr (_("Opened log file %s\n"), filename);
|
||||
g_printerr ("Opened log file %s\n", filename);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
@ -192,6 +193,18 @@ meta_set_replace_current_wm (gboolean setting)
|
||||
replace_current = setting;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_is_wayland_compositor (void)
|
||||
{
|
||||
return is_wayland_compositor;
|
||||
}
|
||||
|
||||
void
|
||||
meta_set_is_wayland_compositor (gboolean value)
|
||||
{
|
||||
is_wayland_compositor = value;
|
||||
}
|
||||
|
||||
char *
|
||||
meta_g_utf8_strndup (const gchar *src,
|
||||
gsize n)
|
||||
@ -259,7 +272,7 @@ meta_debug_spew_real (const char *format, ...)
|
||||
out = logfile ? logfile : stderr;
|
||||
|
||||
if (no_prefix == 0)
|
||||
utf8_fputs (_("Window manager: "), out);
|
||||
utf8_fputs ("Window manager: ", out);
|
||||
utf8_fputs (str, out);
|
||||
|
||||
fflush (out);
|
||||
@ -409,7 +422,7 @@ meta_bug (const char *format, ...)
|
||||
#endif
|
||||
|
||||
if (no_prefix == 0)
|
||||
utf8_fputs (_("Bug in window manager: "), out);
|
||||
utf8_fputs ("Bug in window manager: ", out);
|
||||
utf8_fputs (str, out);
|
||||
|
||||
fflush (out);
|
||||
@ -440,7 +453,7 @@ meta_warning (const char *format, ...)
|
||||
#endif
|
||||
|
||||
if (no_prefix == 0)
|
||||
utf8_fputs (_("Window manager warning: "), out);
|
||||
utf8_fputs ("Window manager warning: ", out);
|
||||
utf8_fputs (str, out);
|
||||
|
||||
fflush (out);
|
||||
@ -468,7 +481,7 @@ meta_fatal (const char *format, ...)
|
||||
#endif
|
||||
|
||||
if (no_prefix == 0)
|
||||
utf8_fputs (_("Window manager error: "), out);
|
||||
utf8_fputs ("Window manager error: ", out);
|
||||
utf8_fputs (str, out);
|
||||
|
||||
fflush (out);
|
||||
|
@ -38,10 +38,15 @@
|
||||
#include "screen-private.h"
|
||||
#include <meta/util.h>
|
||||
#include "stack.h"
|
||||
#include "iconcache.h"
|
||||
#include <X11/Xutil.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "x11/iconcache.h"
|
||||
#include "x11/group-private.h"
|
||||
|
||||
#include "wayland/meta-wayland-types.h"
|
||||
|
||||
typedef struct _MetaWindowQueue MetaWindowQueue;
|
||||
|
||||
@ -60,13 +65,29 @@ typedef enum {
|
||||
|
||||
#define NUMBER_OF_QUEUES 3
|
||||
|
||||
|
||||
typedef enum {
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0,
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1,
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
|
||||
} MetaBypassCompositorHintValue;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_IS_CONFIGURE_REQUEST = 1 << 0,
|
||||
META_DO_GRAVITY_ADJUST = 1 << 1,
|
||||
META_IS_USER_ACTION = 1 << 2,
|
||||
META_IS_MOVE_ACTION = 1 << 3,
|
||||
META_IS_RESIZE_ACTION = 1 << 4,
|
||||
META_IS_WAYLAND_RESIZE = 1 << 5
|
||||
} MetaMoveResizeFlags;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_MOVE_RESIZE_RESULT_MOVED = 1 << 0,
|
||||
META_MOVE_RESIZE_RESULT_RESIZED = 1 << 1,
|
||||
META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2,
|
||||
} MetaMoveResizeResultFlags;
|
||||
|
||||
struct _MetaWindow
|
||||
{
|
||||
GObject parent_instance;
|
||||
@ -75,25 +96,24 @@ struct _MetaWindow
|
||||
MetaScreen *screen;
|
||||
const MetaMonitorInfo *monitor;
|
||||
MetaWorkspace *workspace;
|
||||
MetaWindowClientType client_type;
|
||||
MetaWaylandSurface *surface;
|
||||
Window xwindow;
|
||||
/* may be NULL! not all windows get decorated */
|
||||
MetaFrame *frame;
|
||||
int depth;
|
||||
Visual *xvisual;
|
||||
Colormap colormap;
|
||||
char *desc; /* used in debug spew */
|
||||
char *title;
|
||||
|
||||
char *icon_name;
|
||||
GdkPixbuf *icon;
|
||||
GdkPixbuf *mini_icon;
|
||||
MetaIconCache icon_cache;
|
||||
Pixmap wm_hints_pixmap;
|
||||
Pixmap wm_hints_mask;
|
||||
|
||||
|
||||
MetaWindowType type;
|
||||
Atom type_atom;
|
||||
|
||||
|
||||
/* NOTE these five are not in UTF-8, we just treat them as random
|
||||
* binary data
|
||||
*/
|
||||
@ -119,6 +139,7 @@ struct _MetaWindow
|
||||
Window xtransient_for;
|
||||
Window xgroup_leader;
|
||||
Window xclient_leader;
|
||||
MetaWindow *transient_for;
|
||||
|
||||
/* Initial workspace property */
|
||||
int initial_workspace;
|
||||
@ -153,8 +174,8 @@ struct _MetaWindow
|
||||
/* Whether we're fullscreen */
|
||||
guint fullscreen : 1;
|
||||
|
||||
/* Whether the urgent flag of WM_HINTS is set */
|
||||
guint wm_hints_urgent : 1;
|
||||
/* Whether the window is marked as urgent */
|
||||
guint urgent : 1;
|
||||
|
||||
/* Whether we have to fullscreen after placement */
|
||||
guint fullscreen_after_placement : 1;
|
||||
@ -199,10 +220,18 @@ struct _MetaWindow
|
||||
*/
|
||||
guint hidden : 1;
|
||||
|
||||
/* Whether the compositor thinks the window is visible
|
||||
/* Whether the compositor thinks the window is visible.
|
||||
* This should match up with calls to meta_compositor_show_window /
|
||||
* meta_compositor_hide_window.
|
||||
*/
|
||||
guint visible_to_compositor : 1;
|
||||
|
||||
/* Whether the compositor knows about the window.
|
||||
* This should match up with calls to meta_compositor_add_window /
|
||||
* meta_compositor_remove_window.
|
||||
*/
|
||||
guint known_to_compositor : 1;
|
||||
|
||||
/* When we next show or hide the window, what effect we should
|
||||
* tell the compositor to perform.
|
||||
*/
|
||||
@ -232,7 +261,7 @@ struct _MetaWindow
|
||||
/* These are the flags from WM_PROTOCOLS */
|
||||
guint take_focus : 1;
|
||||
guint delete_window : 1;
|
||||
guint net_wm_ping : 1;
|
||||
guint can_ping : 1;
|
||||
/* Globally active / No input */
|
||||
guint input : 1;
|
||||
|
||||
@ -256,13 +285,6 @@ struct _MetaWindow
|
||||
guint has_move_func : 1;
|
||||
guint has_resize_func : 1;
|
||||
guint has_fullscreen_func : 1;
|
||||
|
||||
/* Weird "_NET_WM_STATE_MODAL" flag */
|
||||
guint wm_state_modal : 1;
|
||||
|
||||
/* TRUE if the client forced these on */
|
||||
guint wm_state_skip_taskbar : 1;
|
||||
guint wm_state_skip_pager : 1;
|
||||
|
||||
/* Computed whether to skip taskbar or not */
|
||||
guint skip_taskbar : 1;
|
||||
@ -316,15 +338,6 @@ struct _MetaWindow
|
||||
|
||||
/* Transient parent is a root window */
|
||||
guint transient_parent_is_root_window : 1;
|
||||
|
||||
/* Info on which props we got our attributes from */
|
||||
guint using_net_wm_name : 1; /* vs. plain wm_name */
|
||||
guint using_net_wm_visible_name : 1; /* tracked so we can clear it */
|
||||
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
|
||||
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
|
||||
|
||||
/* icon props have changed */
|
||||
guint need_reread_icon : 1;
|
||||
|
||||
/* if TRUE, window was maximized at start of current grab op */
|
||||
guint shaken_loose : 1;
|
||||
@ -341,6 +354,10 @@ struct _MetaWindow
|
||||
/* whether or not the window is from a program running on another machine */
|
||||
guint is_remote : 1;
|
||||
|
||||
/* Used for Wayland -- surfaces can behave as if they were unmapped if
|
||||
* they have a NULL buffer attached... */
|
||||
guint surface_mapped;
|
||||
|
||||
/* if non-NULL, the bounds of the window frame */
|
||||
cairo_region_t *frame_bounds;
|
||||
|
||||
@ -398,6 +415,12 @@ struct _MetaWindow
|
||||
*/
|
||||
MetaRectangle rect;
|
||||
|
||||
/* The size and position we want the window to be (i.e. what we last asked
|
||||
* the client to configure).
|
||||
* This is only used for wayland clients.
|
||||
*/
|
||||
MetaRectangle expected_rect;
|
||||
|
||||
gboolean has_custom_frame_extents;
|
||||
GtkBorder custom_frame_extents;
|
||||
|
||||
@ -415,8 +438,6 @@ struct _MetaWindow
|
||||
* gives the position and size of the client window (i.e. ignoring
|
||||
* the frame).
|
||||
*
|
||||
* Position valid if user_has_moved, size valid if user_has_resized
|
||||
*
|
||||
* Position always in root coords, unlike window->rect.
|
||||
*/
|
||||
MetaRectangle user_rect;
|
||||
@ -455,10 +476,24 @@ struct _MetaWindowClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*workspace_changed) (MetaWindow *window, int old_workspace);
|
||||
void (*focus) (MetaWindow *window);
|
||||
void (*raised) (MetaWindow *window);
|
||||
void (*unmanaged) (MetaWindow *window);
|
||||
void (*manage) (MetaWindow *window);
|
||||
void (*unmanage) (MetaWindow *window);
|
||||
void (*ping) (MetaWindow *window,
|
||||
guint32 serial);
|
||||
void (*delete) (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
void (*kill) (MetaWindow *window);
|
||||
void (*focus) (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
void (*move_resize_internal) (MetaWindow *window,
|
||||
int gravity,
|
||||
MetaRectangle requested_rect,
|
||||
MetaRectangle constrained_rect,
|
||||
MetaMoveResizeFlags flags,
|
||||
MetaMoveResizeResultFlags *result);
|
||||
void (*get_default_skip_hints) (MetaWindow *window,
|
||||
gboolean *skip_taskbar_out,
|
||||
gboolean *skip_pager_out);
|
||||
};
|
||||
|
||||
/* These differ from window->has_foo_func in that they consider
|
||||
@ -486,10 +521,22 @@ struct _MetaWindowClass
|
||||
#define META_WINDOW_ALLOWS_HORIZONTAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_width < (w)->size_hints.max_width)
|
||||
#define META_WINDOW_ALLOWS_VERTICAL_RESIZE(w) (META_WINDOW_ALLOWS_RESIZE_EXCEPT_HINTS (w) && (w)->size_hints.min_height < (w)->size_hints.max_height)
|
||||
|
||||
MetaWindow* meta_window_new (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
MetaCompEffect effect);
|
||||
MetaWindow * _meta_window_shared_new (MetaDisplay *display,
|
||||
MetaScreen *screen,
|
||||
MetaWindowClientType client_type,
|
||||
MetaWaylandSurface *surface,
|
||||
Window xwindow,
|
||||
gulong existing_wm_state,
|
||||
MetaCompEffect effect,
|
||||
XWindowAttributes *attrs);
|
||||
|
||||
MetaWindow * meta_window_x11_new (MetaDisplay *display,
|
||||
Window xwindow,
|
||||
gboolean must_be_viewable,
|
||||
MetaCompEffect effect);
|
||||
MetaWindow * meta_window_wayland_new (MetaDisplay *display,
|
||||
MetaWaylandSurface *surface);
|
||||
|
||||
void meta_window_unmanage (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
void meta_window_calc_showing (MetaWindow *window);
|
||||
@ -539,9 +586,6 @@ void meta_window_change_workspace (MetaWindow *window,
|
||||
/* Return whether the window should be currently mapped */
|
||||
gboolean meta_window_should_be_showing (MetaWindow *window);
|
||||
|
||||
/* See warning in window.c about this function */
|
||||
gboolean __window_is_terminal (MetaWindow *window);
|
||||
|
||||
void meta_window_update_struts (MetaWindow *window);
|
||||
|
||||
/* this gets root coords */
|
||||
@ -575,12 +619,6 @@ void meta_window_get_geometry (MetaWindow *window,
|
||||
|
||||
void meta_window_update_unfocused_button_grabs (MetaWindow *window);
|
||||
|
||||
/* Sends a client message */
|
||||
void meta_window_send_icccm_message (MetaWindow *window,
|
||||
Atom atom,
|
||||
guint32 timestamp);
|
||||
|
||||
|
||||
void meta_window_move_resize_request(MetaWindow *window,
|
||||
guint value_mask,
|
||||
int gravity,
|
||||
@ -588,12 +626,11 @@ void meta_window_move_resize_request(MetaWindow *window,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
gboolean meta_window_configure_request (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_property_notify (MetaWindow *window,
|
||||
XEvent *event);
|
||||
gboolean meta_window_client_message (MetaWindow *window,
|
||||
XEvent *event);
|
||||
void meta_window_move_resize_wayland (MetaWindow *window,
|
||||
int width,
|
||||
int height,
|
||||
int dx,
|
||||
int dy);
|
||||
void meta_window_set_focused_internal (MetaWindow *window,
|
||||
gboolean focused);
|
||||
|
||||
@ -607,16 +644,15 @@ void meta_window_show_menu (MetaWindow *window,
|
||||
int button,
|
||||
guint32 timestamp);
|
||||
|
||||
void meta_window_set_gravity (MetaWindow *window,
|
||||
int gravity);
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
void meta_window_update_sync_request_counter (MetaWindow *window,
|
||||
gint64 new_counter_value);
|
||||
#endif /* HAVE_XSYNC */
|
||||
|
||||
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
||||
XIDeviceEvent *xev);
|
||||
void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
|
||||
const ClutterEvent *event);
|
||||
void meta_window_handle_mouse_grab_op_xevent (MetaWindow *window,
|
||||
XIDeviceEvent *xevent);
|
||||
|
||||
GList* meta_window_get_workspaces (MetaWindow *window);
|
||||
|
||||
@ -652,7 +688,8 @@ void meta_window_update_layer (MetaWindow *window);
|
||||
|
||||
void meta_window_recalc_features (MetaWindow *window);
|
||||
|
||||
void meta_window_recalc_window_type (MetaWindow *window);
|
||||
void meta_window_set_type (MetaWindow *window,
|
||||
MetaWindowType type);
|
||||
|
||||
void meta_window_frame_size_changed (MetaWindow *window);
|
||||
|
||||
@ -664,8 +701,6 @@ void meta_window_set_user_time (MetaWindow *window,
|
||||
|
||||
void meta_window_update_icon_now (MetaWindow *window);
|
||||
|
||||
void meta_window_update_role (MetaWindow *window);
|
||||
void meta_window_update_net_wm_type (MetaWindow *window);
|
||||
void meta_window_update_for_monitors_changed (MetaWindow *window);
|
||||
void meta_window_update_on_all_workspaces (MetaWindow *window);
|
||||
|
||||
@ -679,18 +714,56 @@ void meta_window_compute_tile_match (MetaWindow *window);
|
||||
|
||||
gboolean meta_window_updates_are_frozen (MetaWindow *window);
|
||||
|
||||
void meta_window_update_opaque_region_x11 (MetaWindow *window);
|
||||
void meta_window_update_input_region_x11 (MetaWindow *window);
|
||||
void meta_window_update_shape_region_x11 (MetaWindow *window);
|
||||
void meta_window_set_title (MetaWindow *window,
|
||||
const char *title);
|
||||
void meta_window_set_wm_class (MetaWindow *window,
|
||||
const char *wm_class,
|
||||
const char *wm_instance);
|
||||
void meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
||||
const char *application_id,
|
||||
const char *unique_bus_name,
|
||||
const char *appmenu_path,
|
||||
const char *menubar_path,
|
||||
const char *application_object_path,
|
||||
const char *window_object_path);
|
||||
|
||||
void meta_window_set_transient_for (MetaWindow *window,
|
||||
MetaWindow *parent);
|
||||
|
||||
void meta_window_set_opacity (MetaWindow *window,
|
||||
guint opacity);
|
||||
|
||||
void meta_window_set_custom_frame_extents (MetaWindow *window,
|
||||
GtkBorder *extents);
|
||||
|
||||
void meta_window_handle_enter (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
guint root_x,
|
||||
guint root_y);
|
||||
|
||||
void meta_window_set_surface_mapped (MetaWindow *window,
|
||||
gboolean surface_mapped);
|
||||
|
||||
Window meta_window_get_toplevel_xwindow (MetaWindow *window);
|
||||
|
||||
void meta_window_get_client_area_rect (const MetaWindow *window,
|
||||
cairo_rectangle_int_t *rect);
|
||||
|
||||
void meta_window_activate_full (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
MetaClientType source_indication,
|
||||
MetaWorkspace *workspace);
|
||||
|
||||
gboolean meta_window_is_client_decorated (MetaWindow *window);
|
||||
|
||||
void meta_window_update_monitor (MetaWindow *window);
|
||||
|
||||
void meta_window_set_urgent (MetaWindow *window,
|
||||
gboolean urgent);
|
||||
|
||||
void meta_window_update_resize (MetaWindow *window,
|
||||
gboolean snap,
|
||||
int x, int y,
|
||||
gboolean force);
|
||||
|
||||
#endif
|
||||
|
3795
src/core/window.c
3795
src/core/window.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user