Compare commits

..

4 Commits

Author SHA1 Message Date
a3a2109c0c Fix input and bounding shapes
1) We need to select for shape events
2) For decorated windows, we don't want to apply any input
   shape, because the frame is always rectangular and eats
   all the input
3) For undecorated windows, the "has input shape" check is
   wrong if the window has a bounding shape but not an input
   shape
2014-02-25 01:16:13 +01:00
bdbeafc222 MetaWindowActor: replace MetaSurfaceActorEmpty with no MSA at all
Have MetaWindowActor cope with having a NULL surface actor, and
drop the Empty class.
2014-02-24 22:40:43 +01:00
89ca36818a MetaSurfaceActor: move freeze accounting to MetaWindowActor
Turns out we only ever need to freeze/thaw whole windows, not
surfaces or subsurfaces.
This will allow removing the surface actor without losing
the count.
2014-02-24 22:00:12 +01:00
fe1a58b459 compositor: Add a new MetaSurfaceActorEmpty
This will be used in the interim before MetaSurfaceActorWayland
we set_window_id is called. This is somewhat expensive and hacky,
but all other attempts to prevent either MetaWindowActor or
MetaWindow from created prematurely, e.g. before we have a
set_window_id have failed.
2014-02-24 14:46:19 -05:00
165 changed files with 32737 additions and 9839 deletions

22
.gitignore vendored
View File

@ -75,15 +75,15 @@ src/mutter-enum-types.[ch]
src/stamp-mutter-enum-types.h
src/mutter-marshal.[ch]
src/stamp-mutter-marshal.h
src/meta-dbus-display-config.[ch]
src/meta-dbus-xrandr.[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
src/wayland/gtk-shell-protocol.c
src/wayland/gtk-shell-server-protocol.h
src/wayland/xdg-shell-protocol.c
src/wayland/xdg-shell-server-protocol.h
src/wayland/xserver-protocol.c
src/wayland/xserver-server-protocol.h
doc/reference/*.args
doc/reference/*.bak
doc/reference/*.hierarchy
@ -101,11 +101,3 @@ 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

1
AUTHORS Normal file
View File

@ -0,0 +1 @@
Havoc Pennington <hp@redhat.com>

159
COMPLIANCE Normal file
View File

@ -0,0 +1,159 @@
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

15414
ChangeLog Normal file

File diff suppressed because it is too large Load Diff

1297
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

298
HACKING Normal file
View File

@ -0,0 +1,298 @@
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.

8
MAINTAINERS Normal file
View File

@ -0,0 +1,8 @@
Tomas Frydrych
Email: tf linux intel com
Userid: tomasf
Owen Taylor
Email: otaylor redhat com
Userid: otaylor

43
METACITY_MAINTAINERS Normal file
View File

@ -0,0 +1,43 @@
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

View File

@ -1,5 +1,7 @@
SUBDIRS=src po doc
SUBDIRS=src protocol po doc
EXTRA_DIST = HACKING MAINTAINERS rationales.txt
DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache

33
NEWS
View File

@ -1,36 +1,3 @@
3.12.0
======
* Fix grab issue with SSD xwayland windows [Rui; #726123]
* Misc. bug fixes [Jasper, Ray, Rui, Florian; #727011]
Contributors:
Rui Matos, Florian Müllner, Jasper St. Pierre, Ray Strode
3.11.92
=======
* Fix identification of CSD windows [Owen; #723029]
* Update keyboard state unconditionally [Rui; #722847]
* Misc bug fixes and cleanups [Owen, Rui, Giovanni, Matthias, Adel, Ryan,
Jasper, Marek, Florian; #723580, #726123, #726683]
Contributors:
Giovanni Campagna, Marek Chalupa, Matthias Clasen, Adel Gadllah, Ryan Lortie,
Rui Matos, Florian Müllner, Jasper St. Pierre, Owen W. Taylor
3.11.91
=======
* Don't use keysym to match keybindings [Rui; #678001]
* Fix message tray icons showing up blank (again) [Adel; #725180]
* 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 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, Owen W. Taylor
3.11.90
=======
* Fix double-scaling on high DPI resolutions [Adel; #723931]

416
README Normal file
View File

@ -0,0 +1,416 @@
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.

View File

@ -5,7 +5,7 @@ srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="mutter"
REQUIRED_AUTOMAKE_VERSION=1.10
REQUIRED_AUTOMAKE_VERSION=1.13
(test -f $srcdir/configure.ac \
&& test -d $srcdir/src) || {

View File

@ -2,8 +2,8 @@ AC_PREREQ(2.50)
AC_CONFIG_MACRO_DIR([m4])
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [12])
m4_define([mutter_micro_version], [0])
m4_define([mutter_minor_version], [11])
m4_define([mutter_micro_version], [90])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -16,7 +16,7 @@ AC_INIT([mutter], [mutter_version],
AC_CONFIG_SRCDIR(src/core/display.c)
AC_CONFIG_HEADERS(config.h)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar subdir-objects])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AM_MAINTAINER_MODE([enable])
@ -78,7 +78,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.17.5
$CLUTTER_PACKAGE >= 1.17.1
cogl-1.0 >= 1.17.1
upower-glib >= 0.99.0
gnome-desktop-3.0
@ -133,7 +133,7 @@ AC_ARG_WITH([wayland-protocols],
AC_ARG_WITH([xwayland-path],
[AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])],
[XWAYLAND_PATH="$withval"],
[XWAYLAND_PATH="$bindir/Xwayland"])
[XWAYLAND_PATH="$bindir/Xorg"])
AM_GLIB_GNU_GETTEXT
@ -142,6 +142,11 @@ AM_GLIB_GNU_GETTEXT
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
saved_LIBS="$LIBS"
LIBS="$LIBS $MUTTER_LAUNCH"
AC_CHECK_FUNCS([sd_session_get_vt])
LIBS="$saved_LIBS"
# Unconditionally use this dir to avoid a circular dep with gnomecc
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
AC_SUBST(GNOME_KEYBINDINGS_KEYSDIR)
@ -453,6 +458,7 @@ doc/reference/meta-docs.sgml
src/Makefile
src/libmutter-wayland.pc
src/compositor/plugins/Makefile
protocol/Makefile
po/Makefile.in
])
@ -480,6 +486,7 @@ mutter-wayland-$VERSION
Session management: ${found_sm}
Shape extension: ${found_shape}
Xsync: ${found_xsync}
Xcursor: ${have_xcursor}
"

View File

@ -1,4 +1,4 @@
SUBDIRS = man reference
EXTRA_DIST=theme-format.txt dialogs.txt code-overview.txt \
how-to-get-focus-right.txt rationales.txt
how-to-get-focus-right.txt

View File

@ -16,11 +16,11 @@ src/core/monitor.c
src/core/mutter.c
src/core/prefs.c
src/core/screen.c
src/x11/session.c
src/core/session.c
src/core/util.c
src/core/window.c
src/x11/window-props.c
src/x11/xprops.c
src/core/window-props.c
src/core/xprops.c
src/mutter-wayland.desktop.in
src/org.gnome.mutter.gschema.xml.in
src/org.gnome.mutter.wayland.gschema.xml.in

7
protocol/Makefile.am Normal file
View File

@ -0,0 +1,7 @@
NULL =
EXTRA_DIST = \
gtk-shell.xml \
xdg-shell.xml \
xserver.xml \
$(NULL)

View File

@ -40,22 +40,19 @@
<enum name="version">
<description summary="latest protocol version">
The 'current' member of this enum gives the version of the
protocol. Implementations can compare this to the version
they implement using static_assert to ensure the protocol and
implementation versions match.
Use this enum to check the protocol version, and it will be updated
automatically.
</description>
<entry name="current" value="3" summary="Always the latest version"/>
<entry name="current" value="2" summary="Always the latest version"/>
</enum>
<request name="use_unstable_version">
<description summary="enable use of this unstable version">
Negotiate the unstable version of the interface. This
mechanism is in place to ensure client and server agree on the
unstable versions of the protocol that they speak or exit
cleanly if they don't agree. This request will go away once
the xdg-shell protocol is stable.
Use this request in order to enable use of this interface.
Understand and agree that one is using an unstable interface,
that will likely change in the future, breaking the API.
</description>
<arg name="version" type="int"/>
</request>
@ -278,87 +275,113 @@
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<enum name="state">
<description summary="types of state on the surface">
The different state values used on the surface. This is designed for
state values like maximized, fullscreen. It is paired with the
request_change_state event to ensure that both the client and the
compositor setting the state can be synchronized.
States set in this way are double-buffered. They will get applied on
the next commit.
Desktop environments may extend this enum by taking up a range of
values and documenting the range they chose in this description.
They are not required to document the values for the range that they
chose. Ideally, any good extensions from a desktop environment should
make its way into standardization into this enum.
The current reserved ranges are:
0x0000 - 0x0FFF: xdg-shell core values, documented below.
0x1000 - 0x1FFF: GNOME
<event name="request_set_fullscreen">
<description summary="server requests that the client set fullscreen">
Event sent from the compositor to the client requesting that the client
goes to a fullscreen state. It's the client job to call set_fullscreen
and really trigger the fullscreen state.
</description>
<entry name="maximized" value="1" summary="the surface is maximized">
A non-zero value indicates the surface is maximized. Otherwise,
the surface is unmaximized.
</entry>
<entry name="fullscreen" value="2" summary="the surface is fullscreen">
A non-zero value indicates the surface is fullscreen. Otherwise,
the surface is not fullscreen.
</entry>
</enum>
<request name="request_change_state">
<description summary="client requests to change a surface's state">
This asks the compositor to change the state. If the compositor wants
to change the state, it will send a change_state event with the same
state_type, value, and serial, and the event flow continues as if it
it was initiated by the compositor.
If the compositor does not want to change the state, it will send a
change_state to the client with the old value of the state.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="an event serial">
This serial is so the client can know which change_state event corresponds
to which request_change_state request it sent out.
</arg>
</request>
<event name="change_state">
<description summary="compositor wants to change a surface's state">
This event tells the client to change a surface's state. The client
should respond with an ack_change_state request to the compositor to
guarantee that the compositor knows that the client has seen it.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/>
</event>
<request name="ack_change_state">
<description summary="ack a change_state event">
When a change_state event is received, a client should then ack it
using the ack_change_state request to ensure that the compositor
knows the client has seen the event.
By this point, the state is confirmed, and the next attach should
contain the buffer drawn for the new state value.
The values here need to be the same as the values in the cooresponding
change_state event.
<event name="request_unset_fullscreen">
<description summary="server requests that the client unset fullscreen">
Event sent from the compositor to the client requesting that the client
leaves the fullscreen state. It's the client job to call
unset_fullscreen and really leave the fullscreen state.
</description>
</event>
<request name="set_fullscreen">
<description summary="set the surface state as fullscreen">
Set the surface as fullscreen.
After this request, the compositor should send a configure event
informing the output size.
This request informs the compositor that the next attached buffer
committed will be in a fullscreen state. The buffer size should be the
same size as the size informed in the configure event, if the client
doesn't want to leave any empty area.
In other words: the next attached buffer after set_maximized is the new
maximized buffer. And the surface will be positioned at the maximized
position on commit.
A simple way to synchronize and wait for the correct configure event is
to use a wl_display.sync request right after the set_fullscreen
request. When the sync callback returns, the last configure event
received just before it will be the correct one, and should contain the
right size for the surface to maximize.
Setting one state won't unset another state. Use
xdg_surface.unset_fullscreen for unsetting it.
</description>
</request>
<request name="unset_fullscreen">
<description summary="unset the surface state as fullscreen">
Unset the surface fullscreen state.
Same negotiation as set_fullscreen must be used.
</description>
</request>
<event name="request_set_maximized">
<description summary="server requests that the client set maximized">
Event sent from the compositor to the client requesting that the client
goes to a maximized state. It's the client job to call set_maximized
and really trigger the maximized state.
</description>
</event>
<event name="request_unset_maximized">
<description summary="server requests that the client unset maximized">
Event sent from the compositor to the client requesting that the client
leaves the maximized state. It's the client job to call unset_maximized
and really leave the maximized state.
</description>
</event>
<request name="set_maximized">
<description summary="set the surface state as maximized">
Set the surface as maximized.
After this request, the compositor will send a configure event
informing the output size minus panel and other MW decorations.
This request informs the compositor that the next attached buffer
committed will be in a maximized state. The buffer size should be the
same size as the size informed in the configure event, if the client
doesn't want to leave any empty area.
In other words: the next attached buffer after set_maximized is the new
maximized buffer. And the surface will be positioned at the maximized
position on commit.
A simple way to synchronize and wait for the correct configure event is
to use a wl_display.sync request right after the set_maximized request.
When the sync callback returns, the last configure event received just
before it will be the correct one, and should contain the right size
for the surface to maximize.
Setting one state won't unset another state. Use
xdg_surface.unset_maximized for unsetting it.
</description>
</request>
<request name="unset_maximized">
<description summary="unset the surface state as maximized">
Unset the surface maximized state.
Same negotiation as set_maximized must be used.
</description>
<arg name="state_type" type="uint" summary="the state to set"/>
<arg name="value" type="uint" summary="the value to change the state to"/>
<arg name="serial" type="uint" summary="a serial to pass to change_state"/>
</request>
<request name="set_minimized">
<description summary="minimize the surface">
Minimize the surface.
<description summary="set the surface state as minimized">
Set the surface minimized state.
Setting one state won't unset another state.
</description>
</request>

18
protocol/xserver.xml Normal file
View File

@ -0,0 +1,18 @@
<protocol name="xserver">
<interface name="xserver" version="1">
<request name="set_window_id">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="id" type="uint"/>
</request>
<event name="client">
<arg name="fd" type="fd"/>
</event>
<event name="listen_socket">
<arg name="fd" type="fd"/>
</event>
</interface>
</protocol>

View File

@ -29,18 +29,6 @@
<KeyListEntry name="move-to-workspace-down"
_description="Move window one workspace down" />
<KeyListEntry name="move-to-monitor-left"
_description="Move window one monitor to the left" />
<KeyListEntry name="move-to-monitor-right"
_description="Move window one monitor to the right" />
<KeyListEntry name="move-to-monitor-up"
_description="Move window one monitor up" />
<KeyListEntry name="move-to-monitor-down"
_description="Move window one monitor down" />
<KeyListEntry name="switch-applications"
_description="Switch applications"/>

View File

@ -6,14 +6,12 @@ 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 \
@ -30,55 +28,28 @@ 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)\"
INCLUDES += \
-I$(srcdir)/wayland \
-I$(builddir)/wayland \
-DXWAYLAND_PATH='"@XWAYLAND_PATH@"'
mutter_built_sources = \
$(dbus_idle_built_sources) \
$(dbus_display_config_built_sources) \
$(dbus_xrandr_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
wayland_protocols = \
wayland/protocol/gtk-shell.xml \
wayland/protocol/xdg-shell.xml
wayland/gtk-shell-protocol.c \
wayland/gtk-shell-server-protocol.h \
wayland/xdg-shell-protocol.c \
wayland/xdg-shell-server-protocol.h \
wayland/xserver-protocol.c \
wayland/xserver-server-protocol.h
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/above-tab-keycode.c \
core/async-getprop.c \
core/async-getprop.h \
core/barrier.c \
meta/barrier.h \
core/bell.c \
@ -133,6 +104,7 @@ libmutter_wayland_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 \
@ -140,19 +112,39 @@ libmutter_wayland_la_SOURCES = \
core/display.c \
core/display-private.h \
meta/display.h \
ui/draw-workspace.c \
ui/draw-workspace.h \
core/edge-resistance.c \
core/edge-resistance.h \
core/events.c \
core/events.h \
core/edid-parse.c \
core/edid.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-kms.c \
core/monitor-private.h \
core/monitor-xrandr.c \
core/mutter-Xatomtype.h \
core/place.c \
core/place.h \
core/prefs.c \
@ -161,6 +153,8 @@ libmutter_wayland_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 \
@ -168,11 +162,17 @@ libmutter_wayland_la_SOURCES = \
core/util.c \
meta/util.h \
core/util-private.h \
core/window-props.c \
core/window-props.h \
core/window-x11.c \
core/window-x11.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 \
@ -184,36 +184,17 @@ libmutter_wayland_la_SOURCES = \
ui/metaaccellabel.h \
ui/resizepopup.c \
ui/resizepopup.h \
ui/tabpopup.c \
ui/tabpopup.h \
ui/theme-parser.c \
ui/theme.c \
meta/theme.h \
ui/theme-private.h \
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-xwayland.c \
wayland/meta-wayland-data-device.c \
wayland/meta-wayland-data-device.h \
wayland/meta-wayland-keyboard.c \
@ -228,8 +209,8 @@ libmutter_wayland_la_SOURCES = \
wayland/meta-wayland-surface.h \
wayland/meta-wayland-types.h \
wayland/meta-wayland-versions.h \
wayland/window-wayland.c \
wayland/window-wayland.h
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
@ -286,9 +267,7 @@ 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_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
@ -332,7 +311,7 @@ endif
testboxes_SOURCES = core/testboxes.c
testgradient_SOURCES = ui/testgradient.c
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
testasyncgetprop_SOURCES = core/testasyncgetprop.c
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
@ -383,15 +362,13 @@ EXTRA_DIST=$(desktopfiles_files) \
$(desktopfiles_in_files) \
$(wmproperties_in_files) \
$(xml_in_files) \
$(wayland_protocols) \
org.gnome.mutter.gschema.xml.in \
org.gnome.mutter.wayland.gschema.xml.in \
mutter-schemas.convert \
libmutter-wayland.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in \
org.gnome.Mutter.DisplayConfig.xml \
org.gnome.Mutter.IdleMonitor.xml
xrandr.xml idle-monitor.xml
BUILT_SOURCES = $(mutter_built_sources)
MUTTER_STAMP_FILES = stamp-mutter-enum-types.h
@ -416,24 +393,27 @@ 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_display_config_built_sources = meta-dbus-display-config.c meta-dbus-display-config.h
dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
$(dbus_display_config_built_sources) : Makefile.am org.gnome.Mutter.DisplayConfig.xml
$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
$(AM_V_GEN)gdbus-codegen \
--interface-prefix org.gnome.Mutter \
--c-namespace MetaDBus \
--generate-c-code meta-dbus-display-config \
$(srcdir)/org.gnome.Mutter.DisplayConfig.xml
--generate-c-code meta-dbus-xrandr \
$(srcdir)/xrandr.xml
$(dbus_idle_built_sources) : Makefile.am org.gnome.Mutter.IdleMonitor.xml
$(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
$(AM_V_GEN)gdbus-codegen \
--interface-prefix org.gnome.Mutter \
--c-namespace MetaDBus \
--generate-c-code meta-dbus-idle-monitor \
--c-generate-object-manager \
$(srcdir)/org.gnome.Mutter.IdleMonitor.xml
$(srcdir)/idle-monitor.xml
%-protocol.c : $(srcdir)/wayland/protocol/%.xml
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@

View File

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

View File

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

View File

@ -1,50 +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>
*/
#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 */

View File

@ -1,98 +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>
*/
#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

View File

@ -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>
*/
#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;
}

View File

@ -1,42 +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>
*/
#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 */

View File

@ -1,286 +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
*/
#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);
}

View File

@ -1,65 +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
*/
#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 */

View File

@ -1,367 +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 "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);
}

View File

@ -1,55 +0,0 @@
/* -*- 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 */

View File

@ -1,227 +0,0 @@
/* -*- 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)
{
}

View File

@ -1,40 +0,0 @@
/* -*- 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 */

View File

@ -1,219 +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
*/
#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);
}

View File

@ -1,43 +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
*/
#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 */

View File

@ -1,40 +0,0 @@
/* -*- 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 */

View File

@ -1,366 +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
*/
#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);
}
}

View File

@ -1,49 +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
*/
#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 */

View File

@ -1,40 +0,0 @@
/* -*- 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 */

View File

@ -11,21 +11,35 @@
#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;
};
ClutterActor *stage, *window_group, *top_window_group;
struct _MetaCompScreen
{
MetaScreen *screen;
ClutterActor *stage, *window_group, *top_window_group, *overlay_group;
ClutterActor *background_actor;
GList *windows;
GHashTable *windows_by_xid;
Window output;
CoglOnscreen *onscreen;
@ -43,17 +57,19 @@ struct _MetaCompositor
/* Wait 2ms after vblank before starting to draw next frame */
#define META_SYNC_DELAY 2
void meta_switch_workspace_completed (MetaCompositor *compositor);
void meta_switch_workspace_completed (MetaScreen *screen);
gboolean meta_begin_modal_for_plugin (MetaCompositor *compositor,
gboolean meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp);
void meta_end_modal_for_plugin (MetaCompositor *compositor,
void meta_end_modal_for_plugin (MetaScreen *screen,
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

View File

@ -26,6 +26,8 @@
#include <config.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <clutter/clutter.h>
#include "cogl-utils.h"
@ -753,6 +755,88 @@ 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

View File

@ -37,7 +37,7 @@ static GType plugin_type = G_TYPE_NONE;
struct MetaPluginManager
{
MetaCompositor *compositor;
MetaScreen *screen;
MetaPlugin *plugin;
};
@ -91,7 +91,7 @@ on_confirm_display_change (MetaMonitorManager *monitors,
}
MetaPluginManager *
meta_plugin_manager_new (MetaCompositor *compositor)
meta_plugin_manager_new (MetaScreen *screen)
{
MetaPluginManager *plugin_mgr;
MetaPluginClass *klass;
@ -99,10 +99,8 @@ meta_plugin_manager_new (MetaCompositor *compositor)
MetaMonitorManager *monitors;
plugin_mgr = g_new0 (MetaPluginManager, 1);
plugin_mgr->compositor = compositor;
plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL);
_meta_plugin_set_compositor (plugin, compositor);
plugin_mgr->screen = screen;
plugin_mgr->plugin = plugin = g_object_new (plugin_type, "screen", screen, NULL);
klass = META_PLUGIN_GET_CLASS (plugin);
@ -153,7 +151,7 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = plugin_mgr->compositor->display;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
gboolean retval = FALSE;
if (display->display_opening)
@ -167,6 +165,8 @@ 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,6 +176,8 @@ 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;
@ -183,6 +185,7 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
if (klass->destroy)
{
retval = TRUE;
_meta_plugin_effect_started (plugin);
klass->destroy (plugin, actor);
}
break;
@ -213,7 +216,7 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = plugin_mgr->compositor->display;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
gboolean retval = FALSE;
if (display->display_opening)
@ -227,6 +230,8 @@ 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);
@ -238,6 +243,8 @@ 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);
@ -266,7 +273,7 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = plugin_mgr->compositor->display;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
gboolean retval = FALSE;
if (display->display_opening)
@ -276,6 +283,8 @@ 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);
}
@ -324,7 +333,7 @@ meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr,
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = plugin_mgr->compositor->display;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
@ -343,7 +352,7 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = plugin_mgr->compositor->display;
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;

View File

@ -44,7 +44,7 @@
*/
typedef struct MetaPluginManager MetaPluginManager;
MetaPluginManager * meta_plugin_manager_new (MetaCompositor *compositor);
MetaPluginManager * meta_plugin_manager_new (MetaScreen *screen);
void meta_plugin_manager_load (const gchar *plugin_name);

View File

@ -30,7 +30,6 @@
#include "meta-plugin-manager.h"
#include <meta/screen.h>
#include <meta/display.h>
#include <meta/util.h>
#include <string.h>
#include <X11/Xlib.h>
@ -40,22 +39,98 @@
#include "compositor-private.h"
#include "meta-window-actor-private.h"
#include "meta-monitor-manager.h"
#include "monitor-private.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
{
MetaCompositor *compositor;
MetaScreen *screen;
gint running;
gboolean debug : 1;
};
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)
{
g_type_class_add_private (klass, sizeof (MetaPluginPrivate));
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));
}
static void
@ -64,6 +139,22 @@ 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)
{
@ -75,6 +166,21 @@ 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)
@ -102,7 +208,15 @@ meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
meta_switch_workspace_completed (priv->compositor);
MetaScreen *screen = priv->screen;
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
meta_switch_workspace_completed (screen);
}
static void
@ -110,6 +224,26 @@ 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);
}
@ -176,7 +310,7 @@ meta_plugin_begin_modal (MetaPlugin *plugin,
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return meta_begin_modal_for_plugin (priv->compositor, plugin,
return meta_begin_modal_for_plugin (priv->screen, plugin,
options, timestamp);
}
@ -197,14 +331,16 @@ meta_plugin_end_modal (MetaPlugin *plugin,
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
meta_end_modal_for_plugin (priv->compositor, plugin, timestamp);
meta_end_modal_for_plugin (priv->screen, plugin, timestamp);
}
/**
* meta_plugin_get_screen:
* @plugin: a #MetaPlugin
*
* Gets the #MetaScreen corresponding to a plugin.
* 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.
*
* Return value: (transfer none): the #MetaScreen for the plugin
*/
@ -213,15 +349,7 @@ meta_plugin_get_screen (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
return priv->compositor->display->screen;
}
void
_meta_plugin_set_compositor (MetaPlugin *plugin, MetaCompositor *compositor)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
priv->compositor = compositor;
return priv->screen;
}
void

View File

@ -33,7 +33,6 @@
#include "meta-texture-tower.h"
#include "meta-shaped-texture-private.h"
#include "meta-window-actor-private.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
@ -577,18 +576,8 @@ static cairo_region_t *
effective_unobscured_region (MetaShapedTexture *self)
{
MetaShapedTexturePrivate *priv = self->priv;
ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR (self));
if (clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)))
return NULL;
while (parent && !META_IS_WINDOW_ACTOR (parent))
parent = clutter_actor_get_parent (parent);
if (parent && clutter_actor_has_mapped_clones (parent))
return NULL;
return priv->unobscured_region;
return clutter_actor_has_mapped_clones (CLUTTER_ACTOR (self)) ? NULL : priv->unobscured_region;
}
gboolean

View File

@ -29,30 +29,15 @@
#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)
@ -60,19 +45,16 @@ meta_surface_actor_wayland_process_damage (MetaSurfaceActor *actor,
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)
{
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);
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
@ -80,6 +62,13 @@ meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor)
{
}
static gboolean
meta_surface_actor_wayland_is_argb32 (MetaSurfaceActor *actor)
{
/* XXX -- look at the SHM buffer format. */
return TRUE;
}
static gboolean
meta_surface_actor_wayland_is_visible (MetaSurfaceActor *actor)
{
@ -108,49 +97,24 @@ 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_argb32 = meta_surface_actor_wayland_is_argb32;
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 *
@ -173,16 +137,10 @@ meta_surface_actor_wayland_set_buffer (MetaSurfaceActorWayland *self,
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);
}
if (buffer)
meta_shaped_texture_set_texture (stex, buffer->texture);
else
meta_shaped_texture_set_texture (stex, NULL);
}

View File

@ -29,7 +29,7 @@
#include "meta-surface-actor.h"
#include "wayland/meta-wayland.h"
#include "meta-wayland-private.h"
G_BEGIN_DECLS

View File

@ -28,6 +28,7 @@
#include "meta-surface-actor-x11.h"
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <meta/errors.h>
@ -53,6 +54,7 @@ struct _MetaSurfaceActorX11Private
guint does_full_damage : 1;
/* Other state... */
guint argb32 : 1;
guint received_damage : 1;
guint size_changed : 1;
@ -264,6 +266,28 @@ meta_surface_actor_x11_pre_paint (MetaSurfaceActor *actor)
update_pixmap (self);
}
static void
update_is_argb32 (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = priv->display;
Display *xdisplay = meta_display_get_xdisplay (display);
XRenderPictFormat *format;
format = XRenderFindVisualFormat (xdisplay, priv->window->xvisual);
priv->argb32 = (format && format->type == PictTypeDirect && format->direct.alphaMask);
}
static gboolean
meta_surface_actor_x11_is_argb32 (MetaSurfaceActor *actor)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (actor);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
return priv->argb32;
}
static gboolean
meta_surface_actor_x11_is_visible (MetaSurfaceActor *actor)
{
@ -288,7 +312,7 @@ meta_surface_actor_x11_should_unredirect (MetaSurfaceActor *actor)
if (window->shape_region != NULL)
return FALSE;
if (meta_surface_actor_is_argb32 (actor) && !meta_window_requested_bypass_compositor (window))
if (priv->argb32 && !meta_window_requested_bypass_compositor (window))
return FALSE;
if (!meta_window_is_monitor_sized (window))
@ -363,14 +387,6 @@ meta_surface_actor_x11_dispose (GObject *object)
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)
{
@ -381,13 +397,12 @@ meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass)
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_argb32 = meta_surface_actor_x11_is_argb32;
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
@ -436,10 +451,11 @@ meta_surface_actor_x11_new (MetaWindow *window)
g_signal_connect_object (priv->window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
update_is_argb32 (self);
priv->unredirected = FALSE;
sync_unredirected (self);
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
return META_SURFACE_ACTOR (self);
}

View File

@ -15,6 +15,7 @@
#include <clutter/clutter.h>
#include <meta/meta-shaped-texture.h>
#include "meta-wayland-private.h"
#include "meta-cullable.h"
#include "meta-shaped-texture-private.h"
@ -263,26 +264,7 @@ meta_surface_actor_pre_paint (MetaSurfaceActor *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 ();
}
return META_SURFACE_ACTOR_GET_CLASS (self)->is_argb32 (self);
}
gboolean
@ -330,9 +312,3 @@ 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);
}

View File

@ -6,7 +6,6 @@
#include <config.h>
#include <meta/meta-shaped-texture.h>
#include <meta/window.h>
G_BEGIN_DECLS
@ -29,14 +28,13 @@ struct _MetaSurfaceActorClass
void (* process_damage) (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void (* pre_paint) (MetaSurfaceActor *actor);
gboolean (* is_argb32) (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
@ -52,7 +50,6 @@ 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,

View File

@ -5,6 +5,9 @@
#include <config.h>
#include <wayland-server.h>
#include <meta-wayland-private.h>
#include <X11/extensions/Xdamage.h>
#include <meta/compositor-mutter.h>
#include "meta-surface-actor.h"

View File

@ -20,6 +20,7 @@
#include "frame.h"
#include <meta/window.h>
#include <meta/meta-shaped-texture.h>
#include "xprops.h"
#include "compositor-private.h"
#include "meta-shaped-texture-private.h"
@ -27,18 +28,17 @@
#include "meta-window-actor-private.h"
#include "meta-texture-rectangle.h"
#include "region-utils.h"
#include "meta-monitor-manager.h"
#include "meta-wayland-private.h"
#include "monitor-private.h"
#include "meta-cullable.h"
#include "meta-surface-actor.h"
#include "meta-surface-actor-x11.h"
#include "wayland/meta-wayland-surface.h"
struct _MetaWindowActorPrivate
{
MetaWindow *window;
MetaCompositor *compositor;
MetaWindow *window;
MetaScreen *screen;
MetaSurfaceActor *surface;
@ -371,11 +371,11 @@ meta_window_actor_update_surface (MetaWindowActor *self)
static void
meta_window_actor_constructed (GObject *object)
{
MetaWindowActor *self = META_WINDOW_ACTOR (object);
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
MetaWindowActor *self = META_WINDOW_ACTOR (object);
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
priv->compositor = window->display->compositor;
priv->screen = window->screen;
meta_window_actor_update_surface (self);
@ -389,15 +389,19 @@ meta_window_actor_constructed (GObject *object)
static void
meta_window_actor_dispose (GObject *object)
{
MetaWindowActor *self = META_WINDOW_ACTOR (object);
MetaWindowActor *self = META_WINDOW_ACTOR (object);
MetaWindowActorPrivate *priv = self->priv;
MetaCompositor *compositor = priv->compositor;
MetaScreen *screen;
MetaCompScreen *info;
if (priv->disposed)
return;
priv->disposed = TRUE;
screen = priv->screen;
info = meta_screen_get_compositor_data (screen);
if (priv->send_frame_messages_timer != 0)
{
g_source_remove (priv->send_frame_messages_timer);
@ -412,7 +416,7 @@ meta_window_actor_dispose (GObject *object)
g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref);
g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self);
info->windows = g_list_remove (info->windows, (gconstpointer) self);
g_clear_object (&priv->window);
@ -702,6 +706,7 @@ static gboolean
meta_window_actor_has_shadow (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaWindowType window_type = meta_window_get_window_type (priv->window);
if (priv->no_shadow)
return FALSE;
@ -709,7 +714,7 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
/* Leaving out shadows for maximized and fullscreen windows is an effeciency
* win and also prevents the unsightly effect of the shadow of maximized
* window appearing on an adjacent window */
if ((meta_window_get_maximized (priv->window) == META_MAXIMIZE_BOTH) ||
if ((meta_window_get_maximized (priv->window) == (META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL)) ||
meta_window_is_fullscreen (priv->window))
return FALSE;
@ -740,6 +745,25 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
if (priv->window->override_redirect)
return TRUE;
/*
* Don't put shadow around DND icon windows
*/
if (window_type == META_WINDOW_DND ||
window_type == META_WINDOW_DESKTOP)
return FALSE;
if (window_type == META_WINDOW_MENU
#if 0
|| window_type == META_WINDOW_DROPDOWN_MENU
#endif
)
return TRUE;
#if 0
if (window_type == META_WINDOW_TOOLTIP)
return TRUE;
#endif
return FALSE;
}
@ -827,7 +851,8 @@ static void
queue_send_frame_messages_timeout (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaDisplay *display = meta_window_get_display (priv->window);
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
MetaWindow *window = priv->window;
@ -939,10 +964,13 @@ start_simple_effect (MetaWindowActor *self,
gulong event)
{
MetaWindowActorPrivate *priv = self->priv;
MetaCompositor *compositor = priv->compositor;
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
gint *counter = NULL;
gboolean use_freeze_thaw = FALSE;
if (!info->plugin_mgr)
return FALSE;
switch (event)
{
case META_PLUGIN_MINIMIZE:
@ -970,7 +998,9 @@ start_simple_effect (MetaWindowActor *self,
(*counter)++;
if (!meta_plugin_manager_event_simple (compositor->plugin_mgr, self, event))
if (!meta_plugin_manager_event_simple (info->plugin_mgr,
self,
event))
{
(*counter)--;
if (use_freeze_thaw)
@ -1091,11 +1121,15 @@ meta_window_actor_set_unredirected (MetaWindowActor *self,
void
meta_window_actor_destroy (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
MetaCompositor *compositor = priv->compositor;
MetaWindowType window_type = meta_window_get_window_type (window);
MetaWindow *window;
MetaCompScreen *info;
MetaWindowActorPrivate *priv;
MetaWindowType window_type;
priv = self->priv;
window = priv->window;
window_type = meta_window_get_window_type (window);
meta_window_set_compositor_private (window, NULL);
if (priv->send_frame_messages_timer != 0)
@ -1108,7 +1142,8 @@ meta_window_actor_destroy (MetaWindowActor *self)
* We remove the window from internal lookup hashes and thus any other
* unmap events etc fail
*/
compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self);
info = meta_screen_get_compositor_data (priv->screen);
info->windows = g_list_remove (info->windows, (gconstpointer) self);
if (window_type == META_WINDOW_DROPDOWN_MENU ||
window_type == META_WINDOW_POPUP_MENU ||
@ -1169,14 +1204,18 @@ void
meta_window_actor_show (MetaWindowActor *self,
MetaCompEffect effect)
{
MetaWindowActorPrivate *priv = self->priv;
MetaCompositor *compositor = priv->compositor;
gulong event = 0;
MetaWindowActorPrivate *priv;
MetaCompScreen *info;
gulong event;
priv = self->priv;
info = meta_screen_get_compositor_data (priv->screen);
g_return_if_fail (!priv->visible);
self->priv->visible = TRUE;
event = 0;
switch (effect)
{
case META_COMP_EFFECT_CREATE:
@ -1193,7 +1232,7 @@ meta_window_actor_show (MetaWindowActor *self,
g_assert_not_reached();
}
if (compositor->switch_workspace_in_progress ||
if (info->switch_workspace_in_progress ||
event == 0 ||
!start_simple_effect (self, event))
{
@ -1205,9 +1244,12 @@ void
meta_window_actor_hide (MetaWindowActor *self,
MetaCompEffect effect)
{
MetaWindowActorPrivate *priv = self->priv;
MetaCompositor *compositor = priv->compositor;
gulong event = 0;
MetaWindowActorPrivate *priv;
MetaCompScreen *info;
gulong event;
priv = self->priv;
info = meta_screen_get_compositor_data (priv->screen);
g_return_if_fail (priv->visible);
@ -1217,9 +1259,10 @@ meta_window_actor_hide (MetaWindowActor *self,
* hold off on hiding the window, and do it after the workspace
* switch completes
*/
if (compositor->switch_workspace_in_progress)
if (info->switch_workspace_in_progress)
return;
event = 0;
switch (effect)
{
case META_COMP_EFFECT_DESTROY:
@ -1245,8 +1288,7 @@ meta_window_actor_maximize (MetaWindowActor *self,
MetaRectangle *old_rect,
MetaRectangle *new_rect)
{
MetaWindowActorPrivate *priv = self->priv;
MetaCompositor *compositor = priv->compositor;
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
/* The window has already been resized (in order to compute new_rect),
* which by side effect caused the actor to be resized. Restore it to the
@ -1257,7 +1299,8 @@ meta_window_actor_maximize (MetaWindowActor *self,
self->priv->maximize_in_progress++;
meta_window_actor_freeze (self);
if (!meta_plugin_manager_event_maximize (compositor->plugin_mgr,
if (!info->plugin_mgr ||
!meta_plugin_manager_event_maximize (info->plugin_mgr,
self,
META_PLUGIN_MAXIMIZE,
new_rect->x, new_rect->y,
@ -1274,8 +1317,7 @@ meta_window_actor_unmaximize (MetaWindowActor *self,
MetaRectangle *old_rect,
MetaRectangle *new_rect)
{
MetaWindowActorPrivate *priv = self->priv;
MetaCompositor *compositor = priv->compositor;
MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen);
/* The window has already been resized (in order to compute new_rect),
* which by side effect caused the actor to be resized. Restore it to the
@ -1286,7 +1328,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self,
self->priv->unmaximize_in_progress++;
meta_window_actor_freeze (self);
if (!meta_plugin_manager_event_maximize (compositor->plugin_mgr,
if (!info->plugin_mgr ||
!meta_plugin_manager_event_maximize (info->plugin_mgr,
self,
META_PLUGIN_UNMAXIMIZE,
new_rect->x, new_rect->y,
@ -1300,8 +1343,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self,
MetaWindowActor *
meta_window_actor_new (MetaWindow *window)
{
MetaDisplay *display = meta_window_get_display (window);
MetaCompositor *compositor = display->compositor;
MetaScreen *screen = meta_window_get_screen (window);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaWindowActor *self;
MetaWindowActorPrivate *priv;
ClutterActor *window_group;
@ -1326,9 +1369,9 @@ meta_window_actor_new (MetaWindow *window)
meta_window_set_compositor_private (window, G_OBJECT (self));
if (window->layer == META_LAYER_OVERRIDE_REDIRECT)
window_group = compositor->top_window_group;
window_group = info->top_window_group;
else
window_group = compositor->window_group;
window_group = info->window_group;
clutter_actor_add_child (window_group, CLUTTER_ACTOR (self));
@ -1337,7 +1380,7 @@ meta_window_actor_new (MetaWindow *window)
/* Initial position in the stack is arbitrary; stacking will be synced
* before we first paint.
*/
compositor->windows = g_list_append (compositor->windows, self);
info->windows = g_list_append (info->windows, self);
return self;
}
@ -1428,7 +1471,6 @@ meta_window_actor_cull_out (MetaCullable *cullable,
{
MetaWindowActor *self = META_WINDOW_ACTOR (cullable);
meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
meta_window_actor_set_clip_region_beneath (self, clip_region);
}
@ -1671,25 +1713,22 @@ build_and_scan_frame_mask (MetaWindowActor *self,
}
meta_shaped_texture_set_mask_texture (stex, mask_texture);
if (mask_texture)
cogl_object_unref (mask_texture);
cogl_object_unref (mask_texture);
g_free (mask_data);
}
static void
meta_window_actor_update_shape_region (MetaWindowActor *self)
meta_window_actor_update_shape_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *region = NULL;
cairo_rectangle_int_t client_area;
meta_window_get_client_area_rect (priv->window, &client_area);
if (priv->window->frame != NULL && priv->window->shape_region != NULL)
{
region = cairo_region_copy (priv->window->shape_region);
cairo_region_translate (region, client_area.x, client_area.y);
cairo_region_translate (region, client_area->x, client_area->y);
}
else if (priv->window->shape_region != NULL)
{
@ -1700,11 +1739,11 @@ meta_window_actor_update_shape_region (MetaWindowActor *self)
/* If we don't have a shape on the server, that means that
* we have an implicit shape of one rectangle covering the
* entire window. */
region = cairo_region_create_rectangle (&client_area);
region = cairo_region_create_rectangle (client_area);
}
if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL))
build_and_scan_frame_mask (self, &client_area, region);
build_and_scan_frame_mask (self, client_area, region);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
priv->shape_region = region;
@ -1715,23 +1754,41 @@ meta_window_actor_update_shape_region (MetaWindowActor *self)
}
static void
meta_window_actor_update_input_region (MetaWindowActor *self)
meta_window_actor_update_input_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
cairo_region_t *region;
cairo_region_t *region = NULL;
if (window->shape_region && window->input_region)
if (priv->window->frame != NULL)
{
region = cairo_region_copy (window->shape_region);
cairo_region_intersect (region, window->input_region);
region = meta_frame_get_frame_bounds (priv->window->frame);
/* client area is in client window coordinates, so translate the
* input region into that coordinate system and back */
cairo_region_translate (region, -client_area->x, -client_area->y);
cairo_region_union_rectangle (region, client_area);
cairo_region_translate (region, client_area->x, client_area->y);
}
else if (priv->window->shape_region != NULL ||
priv->window->input_region != NULL)
{
if (priv->window->shape_region != NULL)
{
region = cairo_region_copy (priv->window->shape_region);
if (priv->window->input_region != NULL)
cairo_region_intersect (region, priv->window->input_region);
}
else
region = cairo_region_reference (priv->window->input_region);
}
else if (window->shape_region)
region = cairo_region_reference (window->shape_region);
else if (window->input_region)
region = cairo_region_reference (window->input_region);
else
region = NULL;
{
/* If we don't have a shape on the server, that means that
* we have an implicit shape of one rectangle covering the
* entire window. */
region = cairo_region_create_rectangle (client_area);
}
meta_surface_actor_set_input_region (priv->surface, region);
cairo_region_destroy (region);
@ -1746,9 +1803,9 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
if (argb32 && priv->window->opaque_region != NULL)
{
cairo_rectangle_int_t client_area;
MetaFrameBorders borders;
meta_window_get_client_area_rect (priv->window, &client_area);
meta_frame_calc_borders (priv->window->frame, &borders);
/* The opaque region is defined to be a part of the
* window which ARGB32 will always paint with opaque
@ -1761,7 +1818,7 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
* case, graphical glitches will occur.
*/
opaque_region = cairo_region_copy (priv->window->opaque_region);
cairo_region_translate (opaque_region, client_area.x, client_area.y);
cairo_region_translate (opaque_region, borders.total.left, borders.total.top);
cairo_region_intersect (opaque_region, priv->shape_region);
}
else if (argb32)
@ -1777,15 +1834,27 @@ static void
check_needs_reshape (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaFrameBorders borders;
cairo_rectangle_int_t client_area;
if (!priv->needs_reshape)
return;
meta_window_actor_update_shape_region (self);
meta_frame_calc_borders (priv->window->frame, &borders);
client_area.x = borders.total.left;
client_area.y = borders.total.top;
client_area.width = priv->window->rect.width;
if (priv->window->shaded)
client_area.height = 0;
else
client_area.height = priv->window->rect.height;
meta_window_actor_update_shape_region (self, &client_area);
if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
meta_window_actor_update_input_region (self);
meta_window_actor_update_input_region (self, &client_area);
meta_window_actor_update_opaque_region (self);
}
@ -1853,7 +1922,8 @@ static void
do_send_frame_drawn (MetaWindowActor *self, FrameData *frame)
{
MetaWindowActorPrivate *priv = self->priv;
MetaDisplay *display = meta_window_get_display (priv->window);
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XClientMessageEvent ev = { 0, };
@ -1905,7 +1975,7 @@ do_send_frame_timings (MetaWindowActor *self,
gint64 presentation_time)
{
MetaWindowActorPrivate *priv = self->priv;
MetaDisplay *display = meta_window_get_display (priv->window);
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XClientMessageEvent ev = { 0, };

View File

@ -58,6 +58,88 @@
#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
@ -74,8 +156,34 @@ 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);
meta_compositor_flash_screen (display->compositor, display->screen);
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;
}
}
}
/**

View File

@ -425,9 +425,8 @@ 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)) &&
window->decorated &&
meta_rectangle_equal (new, &monitor_info->rect) &&
window->has_fullscreen_func &&
!window->fullscreen)
@ -492,17 +491,12 @@ place_window_if_needed(MetaWindow *window,
!window->minimized &&
!window->fullscreen)
{
MetaRectangle orig_rect;
MetaRectangle placed_rect;
MetaWorkspace *cur_workspace;
const MetaMonitorInfo *monitor_info;
meta_window_get_frame_rect (window, &placed_rect);
orig_rect = info->orig;
extend_by_frame (window, &orig_rect);
meta_window_place (window, orig_rect.x, orig_rect.y,
meta_window_place (window, info->orig.x, info->orig.y,
&placed_rect.x, &placed_rect.y);
did_placement = TRUE;

View File

@ -27,6 +27,16 @@
#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,
META_IS_WAYLAND_RESIZE = 1 << 5
} MetaMoveResizeFlags;
void meta_window_constrain (MetaWindow *window,
MetaMoveResizeFlags flags,
int resize_gravity,

View File

@ -274,7 +274,7 @@ meta_core_lower_beneath_grab_window (Display *xdisplay,
MetaStackWindow stack_sibling;
display = meta_display_for_x_display (xdisplay);
screen = display->screen;
screen = meta_display_screen_for_xwindow (display, xwindow);
grab_window = display->grab_window;
if (grab_window == NULL)
@ -328,7 +328,8 @@ meta_core_maximize (Display *xdisplay,
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_maximize (window, META_MAXIMIZE_BOTH);
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
}
void
@ -341,9 +342,11 @@ meta_core_toggle_maximize_vertically (Display *xdisplay,
meta_window_raise (window);
if (META_WINDOW_MAXIMIZED_VERTICALLY (window))
meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
meta_window_unmaximize (window,
META_MAXIMIZE_VERTICAL);
else
meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
meta_window_maximize (window,
META_MAXIMIZE_VERTICAL);
}
void
@ -356,9 +359,11 @@ meta_core_toggle_maximize_horizontally (Display *xdisplay,
meta_window_raise (window);
if (META_WINDOW_MAXIMIZED_HORIZONTALLY (window))
meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL);
else
meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL);
}
void
@ -371,9 +376,11 @@ meta_core_toggle_maximize (Display *xdisplay,
meta_window_raise (window);
if (META_WINDOW_MAXIMIZED (window))
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
else
meta_window_maximize (window, META_MAXIMIZE_BOTH);
meta_window_maximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
}
void
@ -385,7 +392,8 @@ meta_core_unmaximize (Display *xdisplay,
if (meta_prefs_get_raise_on_click ())
meta_window_raise (window);
meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
meta_window_unmaximize (window,
META_MAXIMIZE_HORIZONTAL | META_MAXIMIZE_VERTICAL);
}
void
@ -603,10 +611,13 @@ meta_core_get_workspace_name_with_index (Display *xdisplay,
int index)
{
MetaDisplay *display;
MetaScreen *screen;
MetaWorkspace *workspace;
display = meta_display_for_x_display (xdisplay);
workspace = meta_screen_get_workspace_by_index (display->screen, index);
screen = meta_display_screen_for_root (display, xroot);
g_assert (screen != NULL);
workspace = meta_screen_get_workspace_by_index (screen, index);
return workspace ? meta_workspace_get_name (workspace) : NULL;
}
@ -627,7 +638,7 @@ meta_core_begin_grab_op (Display *xdisplay,
MetaScreen *screen;
display = meta_display_for_x_display (xdisplay);
screen = display->screen;
screen = meta_display_screen_for_xwindow (display, frame_xwindow);
g_assert (screen != NULL);
@ -667,6 +678,10 @@ 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 &&
@ -711,6 +726,16 @@ 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)
{

View File

@ -193,6 +193,12 @@ 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,

View File

@ -37,7 +37,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "wayland/meta-wayland-surface.h"
#include "meta-wayland-surface.h"
static void meta_window_present_delete_dialog (MetaWindow *window,
guint32 timestamp);
@ -143,7 +143,31 @@ void
meta_window_delete (MetaWindow *window,
guint32 timestamp)
{
META_WINDOW_GET_CLASS (window)->delete (window, timestamp);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
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);
}
else
{
meta_wayland_surface_delete (window->surface);
}
meta_window_check_alive (window, timestamp);
@ -176,10 +200,33 @@ meta_window_delete (MetaWindow *window,
}
}
void
meta_window_kill (MetaWindow *window)
{
META_WINDOW_GET_CLASS (window)->kill (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);
}
void
@ -214,7 +261,8 @@ meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
{
MetaWindow *w = tmp->data;
if (w->transient_for == window && w->res_class &&
if (w->xtransient_for == window->xwindow &&
w->res_class &&
g_ascii_strcasecmp (w->res_class, "mutter-dialog") == 0)
{
meta_window_activate (w, timestamp);

View File

@ -92,7 +92,6 @@ struct _MetaDisplay
Display *xdisplay;
int clutter_event_filter;
GSource *x11_event_source;
Window leader_window;
Window timestamp_pinging_window;
@ -146,12 +145,18 @@ struct _MetaDisplay
* multiple events with the same serial.
*/
guint focused_by_us : 1;
guint static_gravity_works : 1;
/*< private-ish >*/
MetaScreen *screen;
guint error_trap_synced_at_last_pop : 1;
GSList *screens;
MetaScreen *active_screen;
GHashTable *xids;
GHashTable *wayland_windows;
int error_traps;
int (* error_trap_handler) (Display *display,
XErrorEvent *error);
int server_grab_count;
/* serials of leave/unmap events that may
@ -187,6 +192,7 @@ struct _MetaDisplay
/* current window operation */
MetaGrabOp grab_op;
MetaScreen *grab_screen;
MetaWindow *grab_window;
Window grab_xwindow;
int grab_button;
@ -209,6 +215,7 @@ 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;
@ -226,8 +233,8 @@ struct _MetaDisplay
int grab_resize_timeout_id;
/* Keybindings stuff */
GHashTable *key_bindings;
GHashTable *key_bindings_index;
MetaKeyBinding *key_bindings;
int n_key_bindings;
int min_keycode;
int max_keycode;
KeySym *keymap;
@ -254,8 +261,6 @@ struct _MetaDisplay
/* Closing down the display */
int closing;
GSList *error_traps;
/* Managed by group.c */
GHashTable *groups_by_leader;
@ -349,6 +354,10 @@ 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);
@ -448,9 +457,6 @@ 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,
@ -483,16 +489,4 @@ 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

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@
*/
#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 && \
@ -962,9 +963,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->screen->stack,
display->screen->active_workspace);
stacked_windows =
meta_stack_list_windows (display->grab_screen->stack,
display->grab_screen->active_workspace);
/*
* 2nd: we need to separate that stacked list into a list of windows that
@ -1025,7 +1026,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
* by other windows or DOCKS, but that's handled below).
*/
meta_rectangle_intersect (&cur_rect,
&display->screen->rect,
&display->grab_screen->rect,
&reduced);
new_edges = NULL;
@ -1122,8 +1123,8 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
*/
cache_edges (display,
edges,
display->screen->active_workspace->monitor_edges,
display->screen->active_workspace->screen_edges);
display->grab_screen->active_workspace->monitor_edges,
display->grab_screen->active_workspace->screen_edges);
g_list_free (edges);
/*

View File

@ -1,8 +1,9 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
/*
* Copyright (C) 2001 Havoc Pennington, error trapping inspired by GDK
* code copyrighted by the GTK team.
*
* 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,11 +13,9 @@
* 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.
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/**
@ -28,250 +27,42 @@
#include <config.h>
#include <meta/errors.h>
#include "display-private.h"
#include <errno.h>
#include <stdlib.h>
#include <gdk/gdk.h>
/* This is a copy-paste of the error handling code in GDK, modified
* so that it works with mutter's internal structures, since we don't
* have a GDK display open. */
/* compare X sequence numbers handling wraparound */
#define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
typedef struct _GdkErrorTrap GdkErrorTrap;
struct _GdkErrorTrap
{
/* Next sequence when trap was pushed, i.e. first sequence to
* ignore
*/
gulong start_sequence;
/* Next sequence when trap was popped, i.e. first sequence
* to not ignore. 0 if trap is still active.
*/
gulong end_sequence;
/* Most recent error code within the sequence */
int error_code;
};
/* delivers an error event from the error handler in gdkmain-x11.c */
static void
meta_display_error_event (MetaDisplay *display,
XErrorEvent *error)
{
GSList *tmp_list;
gboolean ignore;
ignore = FALSE;
for (tmp_list = display->error_traps;
tmp_list != NULL;
tmp_list = tmp_list->next)
{
GdkErrorTrap *trap;
trap = tmp_list->data;
if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
(trap->end_sequence == 0 ||
SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
{
ignore = TRUE;
trap->error_code = error->error_code;
break; /* only innermost trap gets the error code */
}
}
if (!ignore)
{
gchar buf[64];
gchar *msg;
XGetErrorText (display->xdisplay, error->error_code, buf, 63);
msg =
g_strdup_printf ("mutter received an X Window System error: %s\n"
" (Details: serial %ld error_code %d request_code %d minor_code %d)\n",
buf,
error->serial,
error->error_code,
error->request_code,
error->minor_code);
g_error ("%s", msg);
}
}
static int
gdk_x_error (Display *xdisplay,
XErrorEvent *error)
{
MetaDisplay *display = meta_display_for_x_display (xdisplay);
meta_display_error_event (display, error);
return 0;
}
/* non-GDK previous error handler */
typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
static GdkXErrorHandler _gdk_old_error_handler;
/* number of times we've pushed the GDK error handler */
static int _gdk_error_handler_push_count = 0;
static void
_gdk_x11_error_handler_push (void)
{
GdkXErrorHandler previous;
previous = XSetErrorHandler (gdk_x_error);
if (_gdk_error_handler_push_count > 0)
{
if (previous != gdk_x_error)
g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
}
else
{
_gdk_old_error_handler = previous;
}
_gdk_error_handler_push_count += 1;
}
static void
_gdk_x11_error_handler_pop (void)
{
g_return_if_fail (_gdk_error_handler_push_count > 0);
_gdk_error_handler_push_count -= 1;
if (_gdk_error_handler_push_count == 0)
{
XSetErrorHandler (_gdk_old_error_handler);
_gdk_old_error_handler = NULL;
}
}
static void
delete_outdated_error_traps (MetaDisplay *display)
{
GSList *tmp_list;
gulong processed_sequence;
processed_sequence = XLastKnownRequestProcessed (display->xdisplay);
tmp_list = display->error_traps;
while (tmp_list != NULL)
{
GdkErrorTrap *trap = tmp_list->data;
if (trap->end_sequence != 0 &&
SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
{
GSList *free_me = tmp_list;
tmp_list = tmp_list->next;
display->error_traps = g_slist_delete_link (display->error_traps, free_me);
g_slice_free (GdkErrorTrap, trap);
}
else
{
tmp_list = tmp_list->next;
}
}
}
/* In GTK+-3.0, the error trapping code was significantly rewritten. The new code
* has some neat features (like knowing automatically if a sync is needed or not
* and handling errors asynchronously when the error code isn't needed immediately),
* but it's basically incompatible with the hacks we played with GTK+-2.0 to
* use a custom error handler along with gdk_error_trap_push().
*
* Since the main point of our custom error trap was to get the error logged
* to the right place, with GTK+-3.0 we simply omit our own error handler and
* use the GTK+ handling straight-up.
* (See https://bugzilla.gnome.org/show_bug.cgi?id=630216 for restoring logging.)
*/
void
meta_error_trap_push (MetaDisplay *display)
{
GdkErrorTrap *trap;
delete_outdated_error_traps (display);
/* set up the Xlib callback to tell us about errors */
_gdk_x11_error_handler_push ();
trap = g_slice_new0 (GdkErrorTrap);
trap->start_sequence = XNextRequest (display->xdisplay);
trap->error_code = Success;
display->error_traps =
g_slist_prepend (display->error_traps, trap);
}
static gint
meta_error_trap_pop_internal (MetaDisplay *display,
gboolean need_code)
{
GdkErrorTrap *trap;
GSList *tmp_list;
int result;
g_return_val_if_fail (display->error_traps != NULL, Success);
/* Find the first trap that hasn't been popped already */
trap = NULL; /* quiet gcc */
for (tmp_list = display->error_traps;
tmp_list != NULL;
tmp_list = tmp_list->next)
{
trap = tmp_list->data;
if (trap->end_sequence == 0)
break;
}
g_return_val_if_fail (trap != NULL, Success);
g_assert (trap->end_sequence == 0);
/* May need to sync to fill in trap->error_code if we care about
* getting an error code.
*/
if (need_code)
{
gulong processed_sequence;
gulong next_sequence;
next_sequence = XNextRequest (display->xdisplay);
processed_sequence = XLastKnownRequestProcessed (display->xdisplay);
/* If our last request was already processed, there is no point
* in syncing. i.e. if last request was a round trip (or even if
* we got an event with the serial of a non-round-trip)
*/
if ((next_sequence - 1) != processed_sequence)
{
XSync (display->xdisplay, False);
}
result = trap->error_code;
}
else
{
result = Success;
}
/* record end of trap, giving us a range of
* error sequences we'll ignore.
*/
trap->end_sequence = XNextRequest (display->xdisplay);
/* remove the Xlib callback */
_gdk_x11_error_handler_pop ();
/* we may already be outdated */
delete_outdated_error_traps (display);
return result;
gdk_error_trap_push ();
}
void
meta_error_trap_pop (MetaDisplay *display)
{
meta_error_trap_pop_internal (display, FALSE);
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)
{
return meta_error_trap_pop_internal (display, TRUE);
return gdk_error_trap_pop ();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* 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
* 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 <meta/display.h>
#ifndef META_EVENTS_H
#define META_EVENTS_H
void meta_display_init_events (MetaDisplay *display);
void meta_display_free_events (MetaDisplay *display);
#endif

View File

@ -35,7 +35,8 @@
ButtonPressMask | ButtonReleaseMask | \
PointerMotionMask | PointerMotionHintMask | \
EnterWindowMask | LeaveWindowMask | \
FocusChangeMask)
FocusChangeMask | \
ColormapChangeMask)
void
meta_window_ensure_frame (MetaWindow *window)
@ -92,6 +93,7 @@ meta_window_ensure_frame (MetaWindow *window)
visual = NULL;
frame->xwindow = meta_ui_create_frame_window (window->screen->ui,
window->display->xdisplay,
visual,
frame->rect.x,
frame->rect.y,

View File

@ -230,7 +230,7 @@ read_rgb_icon (MetaDisplay *display,
int mini_w, mini_h;
gulong *data_as_long;
meta_error_trap_push (display);
meta_error_trap_push_with_return (display);
type = None;
data = NULL;
result = XGetWindowProperty (display->xdisplay,
@ -504,7 +504,7 @@ get_kwm_win_icon (MetaDisplay *display,
*pixmap = None;
*mask = None;
meta_error_trap_push (display);
meta_error_trap_push_with_return (display);
icons = NULL;
result = XGetWindowProperty (display->xdisplay, xwindow,
display->atom__KWM_WIN_ICON,

View File

@ -30,7 +30,6 @@
#include <gio/gio.h>
#include <meta/keybindings.h>
typedef struct _MetaKeyHandler MetaKeyHandler;
struct _MetaKeyHandler
{
char *name;
@ -48,48 +47,9 @@ struct _MetaKeyBinding
KeyCode keycode;
unsigned int mask;
MetaVirtualModifier modifiers;
gint flags;
MetaKeyHandler *handler;
};
/**
* MetaKeyCombo:
* @keysym: keysym
* @keycode: keycode
* @modifiers: modifiers
*/
typedef struct _MetaKeyCombo MetaKeyCombo;
struct _MetaKeyCombo
{
unsigned int keysym;
unsigned int keycode;
MetaVirtualModifier modifiers;
};
typedef struct
{
char *name;
GSettings *settings;
MetaKeyBindingAction action;
/*
* A list of MetaKeyCombos. Each of them is bound to
* this keypref. If one has keysym==modifiers==0, it is
* ignored.
*/
GSList *combos;
/* for keybindings that can have shift or not like Alt+Tab */
gboolean add_shift:1;
/* for keybindings that apply only to a window */
gboolean per_window:1;
/* for keybindings not added with meta_display_add_keybinding() */
gboolean builtin:1;
} MetaKeyPref;
void meta_display_init_keys (MetaDisplay *display);
void meta_display_shutdown_keys (MetaDisplay *display);
void meta_screen_grab_keys (MetaScreen *screen);
@ -117,8 +77,5 @@ gboolean meta_prefs_add_keybinding (const char *name,
gboolean meta_prefs_remove_keybinding (const char *name);
GList *meta_prefs_get_keybindings (void);
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

View File

@ -42,7 +42,7 @@
*/
#define _GNU_SOURCE
#define _XOPEN_SOURCE /* for putenv() and some signal-related functions */
#define _SVID_SOURCE /* for putenv() and some signal-related functions */
#include <config.h>
#include <meta/main.h>
@ -50,11 +50,14 @@
#include "display-private.h"
#include <meta/errors.h>
#include "ui.h"
#include "session.h"
#include <meta/prefs.h>
#include <meta/compositor.h>
#include "meta-wayland-private.h"
#include <glib-object.h>
#include <glib-unix.h>
#include <gdk/gdkx.h>
#include <stdlib.h>
#include <sys/types.h>
@ -70,16 +73,12 @@
#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.
*/
@ -191,7 +190,6 @@ 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[] = {
{
@ -235,11 +233,6 @@ static GOptionEntry meta_options[] = {
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}
};
@ -266,6 +259,72 @@ meta_get_option_context (void)
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:
*
@ -342,7 +401,8 @@ meta_init (void)
if (g_getenv ("MUTTER_DEBUG"))
meta_set_debugging (TRUE);
if (opt_display_server)
/* We consider running from mutter-launch equivalent to running from bare metal. */
if (getenv ("WESTON_LAUNCHER_SOCK"))
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
meta_set_is_wayland_compositor (opt_wayland);

View File

@ -0,0 +1,46 @@
/* -*- 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 <clutter/clutter.h>
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
XEvent *xevent);
void meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y);
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_paint (MetaCursorTracker *tracker);
#endif

View File

@ -39,14 +39,76 @@
#include <gbm.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include "meta-cursor-private.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"
#include "meta-monitor-manager.h"
#include "meta-wayland-private.h"
#include "monitor-private.h"
#include "wayland/meta-wayland-private.h"
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
typedef struct {
CoglTexture2D *texture;
struct gbm_bo *bo;
int hot_x, hot_y;
int ref_count;
} MetaCursorReference;
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 *default_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;
};
G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
@ -62,6 +124,360 @@ static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *track
gboolean has_hw_cursor);
static void sync_cursor (MetaCursorTracker *tracker);
static MetaCursorReference *
meta_cursor_reference_ref (MetaCursorReference *self)
{
g_assert (self->ref_count > 0);
self->ref_count++;
return self;
}
static void
meta_cursor_reference_unref (MetaCursorReference *self)
{
self->ref_count--;
if (self->ref_count == 0)
{
cogl_object_unref (self->texture);
if (self->bo)
gbm_bo_destroy (self->bo);
g_slice_free (MetaCursorReference, 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 MetaCursorReference *
meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
MetaCursor cursor)
{
XcursorImage *image;
int width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
MetaCursorReference *self;
image = load_cursor_on_client (tracker->screen->display, cursor);
if (!image)
return NULL;
width = image->width;
height = 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
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->hot_x = image->xhot;
self->hot_y = image->yhot;
clutter_backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
self->texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
rowstride,
(uint8_t*)image->pixels,
NULL);
if (tracker->gbm)
{
if (width > 64 || height > 64)
{
meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
goto out;
}
if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
{
uint32_t buf[64 * 64];
int i;
self->bo = gbm_bo_create (tracker->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 * 64, image->pixels + i * width, width * 4);
gbm_bo_write (self->bo, buf, 64 * 64 * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
out:
XcursorImageDestroy (image);
return self;
}
static MetaCursorReference *
meta_cursor_reference_take_texture (CoglTexture2D *texture)
{
MetaCursorReference *self;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->texture = texture;
return self;
}
static MetaCursorReference *
meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
ClutterBackend *backend;
CoglContext *cogl_context;
MetaCursorReference *self;
CoglPixelFormat cogl_format;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->hot_x = hot_x;
self->hot_y = hot_y;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
int width = wl_shm_buffer_get_width (shm_buffer);
int height = wl_shm_buffer_get_height (shm_buffer);
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
gbm_format = GBM_FORMAT_XRGB8888;
break;
#else
case WL_SHM_FORMAT_ARGB8888:
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
gbm_format = GBM_FORMAT_XRGB8888;
break;
#endif
default:
g_warn_if_reached ();
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
gbm_format = GBM_FORMAT_ARGB8888;
}
self->texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
rowstride,
wl_shm_buffer_get_data (shm_buffer),
NULL);
if (width > 64 || height > 64)
{
meta_warning ("Invalid cursor size (must be at most 64x64), falling back to software (GL) cursors\n");
return self;
}
if (tracker->gbm)
{
if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
{
uint8_t *data;
uint8_t buf[4 * 64 * 64];
int i;
self->bo = gbm_bo_create (tracker->gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
data = wl_shm_buffer_get_data (shm_buffer);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * 64, data + i * rowstride, 4 * width);
gbm_bo_write (self->bo, buf, 64 * 64 * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
}
else
{
int width, height;
self->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
width = cogl_texture_get_width (COGL_TEXTURE (self->texture));
height = cogl_texture_get_height (COGL_TEXTURE (self->texture));
/* 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 self;
}
if (tracker->gbm)
{
self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (!self->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
}
return self;
}
static void
meta_cursor_tracker_init (MetaCursorTracker *self)
{
@ -85,8 +501,8 @@ meta_cursor_tracker_finalize (GObject *object)
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->default_cursors[i])
meta_cursor_reference_unref (self->default_cursors[i]);
if (self->pipeline)
cogl_object_unref (self->pipeline);
@ -153,9 +569,6 @@ make_wayland_cursor_tracker (MetaScreen *screen)
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))
@ -244,22 +657,6 @@ meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
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)
{
@ -316,9 +713,10 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
if (sprite != NULL)
{
MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite,
cursor_image->xhot,
cursor_image->yhot);
MetaCursorReference *cursor = meta_cursor_reference_take_texture (sprite);
cursor->hot_x = cursor_image->xhot;
cursor->hot_y = cursor_image->yhot;
set_window_cursor (tracker, TRUE, cursor);
}
XFree (cursor_image);
@ -338,7 +736,7 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
ensure_xfixes_cursor (tracker);
if (tracker->displayed_cursor)
return meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, NULL, NULL);
return COGL_TEXTURE (tracker->displayed_cursor->texture);
else
return NULL;
}
@ -361,7 +759,13 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
ensure_xfixes_cursor (tracker);
if (tracker->displayed_cursor)
meta_cursor_reference_get_cogl_texture (tracker->displayed_cursor, x, y);
{
MetaCursorReference *displayed_cursor = tracker->displayed_cursor;
if (x)
*x = displayed_cursor->hot_x;
if (y)
*y = displayed_cursor->hot_y;
}
else
{
if (x)
@ -371,21 +775,43 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
}
}
static MetaCursorReference *
ensure_wayland_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{
if (!tracker->default_cursors[cursor])
{
tracker->default_cursors[cursor] = meta_cursor_reference_from_theme (tracker, cursor);
if (!tracker->default_cursors[cursor])
meta_warning ("Failed to load cursor from theme\n");
}
return meta_cursor_reference_ref (tracker->default_cursors[cursor]);
}
void
meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor)
meta_cursor_tracker_set_grab_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{
g_clear_pointer (&tracker->grab_cursor, meta_cursor_reference_unref);
if (cursor)
tracker->grab_cursor = meta_cursor_reference_ref (cursor);
if (cursor != META_CURSOR_DEFAULT)
tracker->grab_cursor = ensure_wayland_cursor (tracker, cursor);
sync_cursor (tracker);
}
void
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor)
meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
MetaCursorReference *cursor;
if (buffer)
cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y);
else
cursor = NULL;
set_window_cursor (tracker, TRUE, cursor);
}
@ -396,23 +822,26 @@ meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker)
}
void
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor)
meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
if (cursor)
tracker->root_cursor = meta_cursor_reference_ref (cursor);
Cursor xcursor;
MetaDisplay *display = tracker->screen->display;
sync_cursor (tracker);
}
/* First create a cursor for X11 applications that don't specify their own */
xcursor = meta_display_create_x_cursor (display, cursor);
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;
XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor);
XFlush (display->xdisplay);
XFreeCursor (display->xdisplay, xcursor);
/* Now update the real root cursor */
if (meta_is_wayland_compositor ())
{
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
tracker->root_cursor = ensure_wayland_cursor (tracker, cursor);
sync_cursor (tracker);
}
}
static void
@ -423,7 +852,7 @@ update_hw_cursor (MetaCursorTracker *tracker)
unsigned int i, n_crtcs;
gboolean enabled;
enabled = should_have_hw_cursor (tracker);
enabled = tracker->displayed_cursor && tracker->displayed_cursor->bo != NULL;
tracker->has_hw_cursor = enabled;
monitors = meta_monitor_manager_get ();
@ -484,23 +913,6 @@ get_displayed_cursor (MetaCursorTracker *tracker)
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)
{
@ -513,7 +925,16 @@ sync_displayed_cursor (MetaCursorTracker *tracker)
if (displayed_cursor)
tracker->displayed_cursor = meta_cursor_reference_ref (displayed_cursor);
update_displayed_cursor (tracker);
if (meta_is_wayland_compositor ())
{
if (displayed_cursor)
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (displayed_cursor->texture));
else
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
update_hw_cursor (tracker);
}
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
}
@ -526,13 +947,14 @@ meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker)
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;
cairo_rectangle_int_t clip = {
.x = tracker->previous_rect.x,
.y = tracker->previous_rect.y,
.width = tracker->previous_rect.width,
.height = tracker->previous_rect.height
};
clutter_actor_queue_redraw_with_clip (stage, &clip);
tracker->previous_is_valid = FALSE;
}
@ -557,15 +979,10 @@ sync_cursor (MetaCursorTracker *tracker)
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));
tracker->current_rect.x = tracker->current_x - displayed_cursor->hot_x;
tracker->current_rect.y = tracker->current_y - displayed_cursor->hot_y;
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (displayed_cursor->texture));
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (displayed_cursor->texture));
}
else
{
@ -626,16 +1043,15 @@ meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
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);
handle = gbm_bo_get_handle (displayed_cursor->bo);
width = gbm_bo_get_width (displayed_cursor->bo);
height = gbm_bo_get_height (displayed_cursor->bo);
hot_x = displayed_cursor->hot_x;
hot_y = displayed_cursor->hot_y;
drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
@ -658,13 +1074,12 @@ get_pointer_position_gdk (int *x,
GdkScreen *gscreen;
gmanager = gdk_display_get_device_manager (gdk_display_get_default ());
gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);
gdevice = gdk_device_manager_get_client_pointer (gmanager);
gdk_device_get_position (gdevice, &gscreen, x, y);
if (mods)
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
}
static void
@ -680,12 +1095,9 @@ get_pointer_position_clutter (int *x,
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);
*x = point.x;
*y = point.y;
*mods = clutter_input_device_get_modifier_state (cdevice);
}
void
@ -727,12 +1139,3 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
tracker->screen->xroot);
}
}
void
meta_cursor_tracker_force_update (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
update_hw_cursor (tracker);
sync_cursor (tracker);
}

View File

@ -1,8 +1,8 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
/*
* Copyright 2013 Red Hat, Inc.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@ -12,7 +12,7 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
@ -20,9 +20,10 @@
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
*/
#ifndef META_IDLE_MONITOR_DBUS_H
#define META_IDLE_MONITOR_DBUS_H
#include <meta/meta-idle-monitor.h>
void meta_idle_monitor_handle_xevent_all (XEvent *xevent);
void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor);
void meta_idle_monitor_init_dbus (void);
#endif

View File

@ -0,0 +1,996 @@
/* -*- 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;
/* Wayland implementation */
guint64 last_event_time;
};
struct _MetaIdleMonitorClass
{
GObjectClass parent_class;
};
typedef struct
{
MetaIdleMonitor *monitor;
guint id;
MetaIdleMonitorWatchFunc callback;
gpointer user_data;
GDestroyNotify notify;
guint64 timeout_msec;
/* x11 */
XSyncAlarm xalarm;
int idle_source_id;
/* wayland */
GSource *timeout_source;
} MetaIdleMonitorWatch;
enum
{
PROP_0,
PROP_DEVICE_ID,
PROP_LAST,
};
static GParamSpec *obj_props[PROP_LAST];
G_DEFINE_TYPE (MetaIdleMonitor, meta_idle_monitor, G_TYPE_OBJECT)
static MetaIdleMonitor *device_monitors[256];
static int device_id_max;
static gint64
_xsyncvalue_to_int64 (XSyncValue value)
{
return ((guint64) XSyncValueHigh32 (value)) << 32
| (guint64) XSyncValueLow32 (value);
}
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
static void
fire_watch (MetaIdleMonitorWatch *watch)
{
MetaIdleMonitor *monitor;
guint id;
gboolean is_user_active_watch;
monitor = watch->monitor;
g_object_ref (monitor);
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);
}
if (watch->timeout_source != NULL)
g_source_destroy (watch->timeout_source);
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);
if (!meta_is_wayland_compositor ())
{
monitor->display = meta_get_display ()->xdisplay;
init_xsync (monitor);
}
}
static void
meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_idle_monitor_dispose;
object_class->constructed = meta_idle_monitor_constructed;
object_class->get_property = meta_idle_monitor_get_property;
object_class->set_property = meta_idle_monitor_set_property;
/**
* MetaIdleMonitor:device_id:
*
* The device to listen to idletime on.
*/
obj_props[PROP_DEVICE_ID] =
g_param_spec_int ("device-id",
"Device ID",
"The device to listen to idletime on",
0, 255, 0,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]);
}
static void
meta_idle_monitor_init (MetaIdleMonitor *monitor)
{
monitor->watches = g_hash_table_new_full (NULL,
NULL,
NULL,
(GDestroyNotify)idle_monitor_watch_free);
monitor->alarms = g_hash_table_new (NULL, NULL);
}
static void
ensure_device_monitor (int device_id)
{
if (device_monitors[device_id])
return;
device_monitors[device_id] = g_object_new (META_TYPE_IDLE_MONITOR, "device-id", device_id, NULL);
device_id_max = MAX (device_id_max, device_id);
}
/**
* meta_idle_monitor_get_core:
*
* Returns: (transfer none): the #MetaIdleMonitor that tracks the server-global
* idletime for all devices. To track device-specific idletime,
* use meta_idle_monitor_get_for_device().
*/
MetaIdleMonitor *
meta_idle_monitor_get_core (void)
{
ensure_device_monitor (0);
return device_monitors[0];
}
/**
* meta_idle_monitor_get_for_device:
* @device_id: the device to get the idle time for.
*
* Returns: (transfer none): a new #MetaIdleMonitor that tracks the
* device-specific idletime for @device. To track server-global idletime
* for all devices, use meta_idle_monitor_get_core().
*/
MetaIdleMonitor *
meta_idle_monitor_get_for_device (int device_id)
{
g_return_val_if_fail (device_id > 0 && device_id < 256, NULL);
ensure_device_monitor (device_id);
return device_monitors[device_id];
}
static gboolean
wayland_dispatch_timeout (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MetaIdleMonitorWatch *watch = user_data;
fire_watch (watch);
g_source_set_ready_time (watch->timeout_source, -1);
return TRUE;
}
static GSourceFuncs wayland_source_funcs = {
NULL, /* prepare */
NULL, /* check */
wayland_dispatch_timeout,
NULL, /* finalize */
};
static 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 (meta_is_wayland_compositor ())
{
if (timeout_msec != 0)
{
GSource *source = g_source_new (&wayland_source_funcs, sizeof (GSource));
g_source_set_callback (source, NULL, watch, NULL);
g_source_set_ready_time (source, monitor->last_event_time + timeout_msec * 1000);
g_source_attach (source, NULL);
g_source_unref (source);
watch->timeout_source = source;
}
}
else if (monitor->user_active_alarm != None)
{
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
{
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 (meta_is_wayland_compositor ())
{
return (g_get_monotonic_time () - monitor->last_event_time) / 1000;
}
else
{
if (!XSyncQueryCounter (monitor->display, monitor->counter, &value))
return -1;
return _xsyncvalue_to_int64 (value);
}
}
typedef struct {
MetaIdleMonitor *monitor;
GList *fired_watches;
} CheckWaylandClosure;
static gboolean
check_wayland_watch (gpointer key,
gpointer value,
gpointer user_data)
{
MetaIdleMonitorWatch *watch = value;
CheckWaylandClosure *closure = user_data;
gboolean steal;
if (watch->timeout_msec == 0)
{
closure->fired_watches = g_list_prepend (closure->fired_watches, watch);
steal = TRUE;
}
else
{
g_source_set_ready_time (watch->timeout_source,
closure->monitor->last_event_time +
watch->timeout_msec * 1000);
steal = FALSE;
}
return steal;
}
static void
fire_wayland_watch (gpointer watch,
gpointer data)
{
fire_watch (watch);
}
void
meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
{
CheckWaylandClosure closure;
monitor->last_event_time = g_get_monotonic_time ();
closure.monitor = monitor;
closure.fired_watches = NULL;
g_hash_table_foreach_steal (monitor->watches, check_wayland_watch, &closure);
g_list_foreach (closure.fired_watches, fire_wayland_watch, NULL);
g_list_free (closure.fired_watches);
}
static gboolean
handle_get_idletime (MetaDBusIdleMonitor *skeleton,
GDBusMethodInvocation *invocation,
MetaIdleMonitor *monitor)
{
guint64 idletime;
idletime = meta_idle_monitor_get_idletime (monitor);
meta_dbus_idle_monitor_complete_get_idletime (skeleton, invocation, idletime);
return TRUE;
}
typedef struct {
MetaDBusIdleMonitor *dbus_monitor;
MetaIdleMonitor *monitor;
char *dbus_name;
guint watch_id;
guint name_watcher_id;
} DBusWatch;
static void
destroy_dbus_watch (gpointer data)
{
DBusWatch *watch = data;
g_object_unref (watch->dbus_monitor);
g_object_unref (watch->monitor);
g_free (watch->dbus_name);
g_bus_unwatch_name (watch->name_watcher_id);
g_slice_free (DBusWatch, watch);
}
static void
dbus_idle_callback (MetaIdleMonitor *monitor,
guint watch_id,
gpointer user_data)
{
DBusWatch *watch = user_data;
GDBusInterfaceSkeleton *skeleton = G_DBUS_INTERFACE_SKELETON (watch->dbus_monitor);
g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (skeleton),
watch->dbus_name,
g_dbus_interface_skeleton_get_object_path (skeleton),
"org.gnome.Mutter.IdleMonitor",
"WatchFired",
g_variant_new ("(u)", watch_id),
NULL);
}
static void
name_vanished_callback (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
DBusWatch *watch = user_data;
meta_idle_monitor_remove_watch (watch->monitor, watch->watch_id);
}
static DBusWatch *
make_dbus_watch (MetaDBusIdleMonitor *skeleton,
GDBusMethodInvocation *invocation,
MetaIdleMonitor *monitor)
{
DBusWatch *watch;
watch = g_slice_new (DBusWatch);
watch->dbus_monitor = g_object_ref (skeleton);
watch->monitor = g_object_ref (monitor);
watch->dbus_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
watch->name_watcher_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation),
watch->dbus_name,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL, /* appeared */
name_vanished_callback,
watch, NULL);
return watch;
}
static gboolean
handle_add_idle_watch (MetaDBusIdleMonitor *skeleton,
GDBusMethodInvocation *invocation,
guint64 interval,
MetaIdleMonitor *monitor)
{
DBusWatch *watch;
watch = make_dbus_watch (skeleton, invocation, monitor);
watch->watch_id = meta_idle_monitor_add_idle_watch (monitor, interval,
dbus_idle_callback, watch, destroy_dbus_watch);
meta_dbus_idle_monitor_complete_add_idle_watch (skeleton, invocation, watch->watch_id);
return TRUE;
}
static gboolean
handle_add_user_active_watch (MetaDBusIdleMonitor *skeleton,
GDBusMethodInvocation *invocation,
MetaIdleMonitor *monitor)
{
DBusWatch *watch;
watch = make_dbus_watch (skeleton, invocation, monitor);
watch->watch_id = meta_idle_monitor_add_user_active_watch (monitor,
dbus_idle_callback, watch,
destroy_dbus_watch);
meta_dbus_idle_monitor_complete_add_user_active_watch (skeleton, invocation, watch->watch_id);
return TRUE;
}
static gboolean
handle_remove_watch (MetaDBusIdleMonitor *skeleton,
GDBusMethodInvocation *invocation,
guint id,
MetaIdleMonitor *monitor)
{
meta_idle_monitor_remove_watch (monitor, id);
meta_dbus_idle_monitor_complete_remove_watch (skeleton, invocation);
return TRUE;
}
static void
create_monitor_skeleton (GDBusObjectManagerServer *manager,
MetaIdleMonitor *monitor,
const char *path)
{
MetaDBusIdleMonitor *skeleton;
MetaDBusObjectSkeleton *object;
skeleton = meta_dbus_idle_monitor_skeleton_new ();
g_signal_connect_object (skeleton, "handle-add-idle-watch",
G_CALLBACK (handle_add_idle_watch), monitor, 0);
g_signal_connect_object (skeleton, "handle-add-user-active-watch",
G_CALLBACK (handle_add_user_active_watch), monitor, 0);
g_signal_connect_object (skeleton, "handle-remove-watch",
G_CALLBACK (handle_remove_watch), monitor, 0);
g_signal_connect_object (skeleton, "handle-get-idletime",
G_CALLBACK (handle_get_idletime), monitor, 0);
object = meta_dbus_object_skeleton_new (path);
meta_dbus_object_skeleton_set_idle_monitor (object, skeleton);
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
GDBusObjectManagerServer *manager)
{
MetaIdleMonitor *monitor;
int device_id;
char *path;
device_id = clutter_input_device_get_device_id (device);
monitor = meta_idle_monitor_get_for_device (device_id);
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
create_monitor_skeleton (manager, monitor, path);
g_free (path);
}
static void
on_device_removed (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
GDBusObjectManagerServer *manager)
{
int device_id;
char *path;
device_id = clutter_input_device_get_device_id (device);
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
g_dbus_object_manager_server_unexport (manager, path);
g_free (path);
g_clear_object (&device_monitors[device_id]);
if (device_id == device_id_max)
device_id_max--;
}
static void
on_bus_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
GDBusObjectManagerServer *manager;
ClutterDeviceManager *device_manager;
MetaIdleMonitor *monitor;
GSList *devices, *iter;
char *path;
manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
/* We never clear the core monitor, as that's supposed to cumulate idle times from
all devices */
monitor = meta_idle_monitor_get_core ();
path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
create_monitor_skeleton (manager, monitor, path);
g_free (path);
device_manager = clutter_device_manager_get_default ();
devices = clutter_device_manager_list_devices (device_manager);
for (iter = devices; iter; iter = iter->next)
on_device_added (device_manager, iter->data, manager);
g_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);
}

View File

@ -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-display-config-shared.h)
/* This file is shared between mutter (src/core/meta-xrandr-shared.h)
and gnome-desktop (libgnome-desktop/meta-xrandr-shared.h).
The canonical place for all changes is mutter.
@ -24,8 +24,8 @@
There should be no includes in this file.
*/
#ifndef META_DISPLAY_CONFIG_SHARED_H
#define META_DISPLAY_CONFIG_SHARED_H
#ifndef META_XRANDR_SHARED_H
#define META_XRANDR_SHARED_H
typedef enum {
META_POWER_SAVE_UNSUPPORTED = -1,
@ -35,4 +35,4 @@ typedef enum {
META_POWER_SAVE_OFF,
} MetaPowerSave;
#endif /* META_DISPLAY_CONFIG_SHARED_H */
#endif

View File

@ -34,14 +34,13 @@
#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.

View File

@ -23,8 +23,6 @@
#include "config.h"
#include "meta-monitor-manager-kms.h"
#include <string.h>
#include <stdlib.h>
#include <clutter/clutter.h>
@ -38,6 +36,7 @@
#include <meta/main.h>
#include <meta/errors.h>
#include "monitor-private.h"
#include "edid.h"
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
@ -651,7 +650,7 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
state = DRM_MODE_DPMS_SUSPEND;
break;
case META_POWER_SAVE_OFF:
state = DRM_MODE_DPMS_OFF;
state = DRM_MODE_DPMS_SUSPEND;
break;
default:
return;

View File

@ -43,9 +43,9 @@
#include "stack-tracker.h"
#include "ui.h"
#include <wayland-server.h>
#include "meta-xrandr-shared.h"
#include "meta-display-config-shared.h"
#include "meta-dbus-display-config.h"
#include "meta-dbus-xrandr.h"
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
typedef struct _MetaMonitorManager MetaMonitorManager;
@ -227,6 +227,8 @@ 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;
@ -333,6 +335,57 @@ 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_MANAGER_KMS (meta_monitor_manager_kms_get_type ())
#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms))
#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS))
#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS))
#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass;
typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms;
GType meta_monitor_manager_kms_get_type (void);
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG))
#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
MetaMonitorConfig *meta_monitor_config_new (void);
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_make_default (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_update_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
void meta_monitor_config_restore_previous (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);

View File

@ -25,8 +25,6 @@
#include "config.h"
#include "meta-monitor-manager-xrandr.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
@ -38,8 +36,9 @@
#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)

View File

@ -25,8 +25,6 @@
#include "config.h"
#include "meta-monitor-manager.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>
@ -35,10 +33,12 @@
#include <meta/main.h>
#include "util-private.h"
#include <meta/errors.h>
#include "meta-monitor-config.h"
#include "backends/native/meta-monitor-manager-kms.h"
#include "backends/x11/meta-monitor-manager-xrandr.h"
#include "meta-monitor-manager-dummy.h"
#include "monitor-private.h"
#include "meta-wayland-private.h"
#include "meta-dbus-xrandr.h"
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
enum {
CONFIRM_DISPLAY_CHANGE,
@ -55,11 +55,196 @@ static int signals[SIGNALS_LAST];
static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface);
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));
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));
static void initialize_dbus_interface (MetaMonitorManager *manager);
static void
read_current_dummy (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
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)
{
@ -183,7 +368,7 @@ get_default_backend (void)
* we're a nested configuration, so return the dummy
* monitor setup. */
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER_DUMMY;
return META_TYPE_MONITOR_MANAGER;
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
@ -195,7 +380,7 @@ get_default_backend (void)
/* 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;
return META_TYPE_MONITOR_MANAGER;
}
#endif
@ -389,20 +574,6 @@ 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)
{
@ -414,8 +585,10 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
object_class->dispose = meta_monitor_manager_dispose;
object_class->finalize = meta_monitor_manager_finalize;
klass->get_edid_file = meta_monitor_manager_real_get_edid_file;
klass->read_edid = meta_monitor_manager_real_read_edid;
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;
signals[CONFIRM_DISPLAY_CHANGE] =
g_signal_new ("confirm-display-change",

View File

@ -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->type == META_WINDOW_MODAL_DIALOG &&
window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
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,11 +699,18 @@ meta_window_place (MetaWindow *window,
goto done_no_constraints;
}
}
if (window->type == META_WINDOW_DIALOG ||
window->type == META_WINDOW_MODAL_DIALOG)
if ((window->type == META_WINDOW_DIALOG ||
window->type == META_WINDOW_MODAL_DIALOG) &&
window->xtransient_for != None)
{
MetaWindow *parent = meta_window_get_transient_for (window);
/* Center horizontally, at top of parent vertically */
MetaWindow *parent;
parent =
meta_display_lookup_x_window (window->display,
window->xtransient_for);
if (parent)
{

View File

@ -57,6 +57,7 @@
#define KEY_OVERLAY_KEY "overlay-key"
#define KEY_WORKSPACES_ONLY_ON_PRIMARY "workspaces-only-on-primary"
#define KEY_NO_TAB_POPUP "no-tab-popup"
/* These are the different schemas we are keeping
* a GSettings instance for */
@ -111,6 +112,8 @@ static char **workspace_names = NULL;
static gboolean workspaces_only_on_primary = FALSE;
static gboolean no_tab_popup = FALSE;
static char *iso_next_group_option = NULL;
static void handle_preference_update_enum (GSettings *settings,
@ -362,6 +365,13 @@ static MetaBoolPreference preferences_bool[] =
},
&workspaces_only_on_primary,
},
{
{ KEY_NO_TAB_POPUP,
SCHEMA_MUTTER,
META_PREF_NO_TAB_POPUP,
},
&no_tab_popup,
},
{
{ "auto-maximize",
SCHEMA_MUTTER,
@ -1803,6 +1813,9 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_WORKSPACES_ONLY_ON_PRIMARY:
return "WORKSPACES_ONLY_ON_PRIMARY";
case META_PREF_NO_TAB_POPUP:
return "NO_TAB_POPUP";
case META_PREF_DRAGGABLE_BORDER_WIDTH:
return "DRAGGABLE_BORDER_WIDTH";
@ -1856,7 +1869,7 @@ init_bindings (void)
pref = g_new0 (MetaKeyPref, 1);
pref->name = g_strdup ("overlay-key");
pref->action = META_KEYBINDING_ACTION_OVERLAY_KEY;
pref->combos = g_slist_prepend (pref->combos, &overlay_key_combo);
pref->bindings = g_slist_prepend (pref->bindings, &overlay_key_combo);
pref->builtin = 1;
g_hash_table_insert (key_bindings, g_strdup ("overlay-key"), pref);
@ -1866,7 +1879,7 @@ static gboolean
update_binding (MetaKeyPref *binding,
gchar **strokes)
{
GSList *old_combos, *a, *b;
GSList *old_bindings, *a, *b;
gboolean changed;
unsigned int keysym;
unsigned int keycode;
@ -1878,8 +1891,8 @@ update_binding (MetaKeyPref *binding,
"Binding \"%s\" has new GSettings value\n",
binding->name);
old_combos = binding->combos;
binding->combos = NULL;
old_bindings = binding->bindings;
binding->bindings = NULL;
for (i = 0; strokes && strokes[i]; i++)
{
@ -1920,17 +1933,17 @@ update_binding (MetaKeyPref *binding,
combo->keysym = keysym;
combo->keycode = keycode;
combo->modifiers = mods;
binding->combos = g_slist_prepend (binding->combos, combo);
binding->bindings = g_slist_prepend (binding->bindings, combo);
meta_topic (META_DEBUG_KEYBINDINGS,
"New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
binding->name, keysym, keycode, mods);
}
binding->combos = g_slist_reverse (binding->combos);
binding->bindings = g_slist_reverse (binding->bindings);
a = old_combos;
b = binding->combos;
a = old_bindings;
b = binding->bindings;
while (TRUE)
{
if ((!a && b) || (a && !b))
@ -1955,7 +1968,7 @@ update_binding (MetaKeyPref *binding,
}
}
g_slist_free_full (old_combos, g_free);
g_slist_free_full (old_bindings, g_free);
return changed;
}
@ -2090,7 +2103,7 @@ meta_prefs_add_keybinding (const char *name,
pref->name = g_strdup (name);
pref->settings = g_object_ref (settings);
pref->action = action;
pref->combos = NULL;
pref->bindings = NULL;
pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0;
pref->builtin = (flags & META_KEY_BINDING_BUILTIN) != 0;
@ -2154,6 +2167,11 @@ meta_prefs_remove_keybinding (const char *name)
return TRUE;
}
/**
* meta_prefs_get_keybindings:
*
* Returns: (element-type MetaKeyPref) (transfer container):
*/
GList *
meta_prefs_get_keybindings ()
{
@ -2254,7 +2272,7 @@ meta_prefs_get_window_binding (const char *name,
if (pref->per_window)
{
GSList *s = pref->combos;
GSList *s = pref->bindings;
while (s)
{
@ -2302,6 +2320,25 @@ meta_prefs_get_workspaces_only_on_primary (void)
return workspaces_only_on_primary;
}
gboolean
meta_prefs_get_no_tab_popup (void)
{
return no_tab_popup;
}
void
meta_prefs_set_no_tab_popup (gboolean whether)
{
MetaBasePreference *pref;
if (find_pref (preferences_bool, sizeof(MetaBoolPreference),
KEY_NO_TAB_POPUP, &pref))
{
g_settings_set_boolean (SETTINGS (pref->schema), KEY_NO_TAB_POPUP, whether);
}
}
int
meta_prefs_get_draggable_border_width (void)
{

View File

@ -36,7 +36,7 @@
#include <X11/Xutil.h>
#include "stack-tracker.h"
#include "ui.h"
#include "meta-monitor-manager.h"
#include "monitor-private.h"
typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
gpointer user_data);
@ -64,6 +64,7 @@ struct _MetaScreen
Visual *default_xvisual;
MetaRectangle rect; /* Size of screen; rect.x & rect.y are always 0 */
MetaUI *ui;
MetaTabPopup *tab_popup, *ws_popup;
guint tile_preview_timeout_id;
@ -82,6 +83,8 @@ struct _MetaScreen
MetaCursorTracker *cursor_tracker;
MetaCursor current_cursor;
Window flash_window;
Window wm_sn_selection_window;
Atom wm_sn_atom;
guint32 wm_sn_timestamp;
@ -116,6 +119,9 @@ 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
@ -144,6 +150,22 @@ void meta_screen_foreach_window (MetaScreen *scree
void meta_screen_update_cursor (MetaScreen *screen);
void meta_screen_tab_popup_create (MetaScreen *screen,
MetaTabList list_type,
MetaTabShowType show_type,
MetaWindow *initial_window);
void meta_screen_tab_popup_forward (MetaScreen *screen);
void meta_screen_tab_popup_backward (MetaScreen *screen);
MetaWindow* meta_screen_tab_popup_get_selected (MetaScreen *screen);
void meta_screen_tab_popup_destroy (MetaScreen *screen);
void meta_screen_workspace_popup_create (MetaScreen *screen,
MetaWorkspace *initial_selection);
void meta_screen_workspace_popup_select (MetaScreen *screen,
MetaWorkspace *workspace);
MetaWorkspace*meta_screen_workspace_popup_get_selected (MetaScreen *screen);
void meta_screen_workspace_popup_destroy (MetaScreen *screen);
void meta_screen_update_tile_preview (MetaScreen *screen,
gboolean delay);
void meta_screen_hide_tile_preview (MetaScreen *screen);

View File

@ -39,9 +39,11 @@
#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"
#include "meta-wayland-private.h"
#include "meta-cursor-tracker-private.h"
#include <X11/extensions/Xinerama.h>
@ -52,8 +54,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "x11/xprops.h"
static char* get_screen_name (MetaDisplay *display,
int number);
@ -308,8 +308,6 @@ set_supported_hint (MetaScreen *screen)
#include <meta/atomnames.h>
#undef item
#undef EWMH_ATOMS_ONLY
screen->display->atom__GTK_FRAME_EXTENTS,
};
XChangeProperty (screen->display->xdisplay, screen->xroot,
@ -560,7 +558,7 @@ meta_screen_new (MetaDisplay *display,
}
/* We want to find out when the current selection owner dies */
meta_error_trap_push (display);
meta_error_trap_push_with_return (display);
attrs.event_mask = StructureNotifyMask;
XChangeWindowAttributes (xdisplay,
current_wm_sn_owner, CWEventMask, &attrs);
@ -619,7 +617,7 @@ meta_screen_new (MetaDisplay *display,
}
/* select our root window events */
meta_error_trap_push (display);
meta_error_trap_push_with_return (display);
/* We need to or with the existing event mask since
* gtk+ may be interested in other events.
@ -690,6 +688,7 @@ 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;
@ -707,6 +706,7 @@ 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);
@ -757,7 +757,11 @@ meta_screen_new (MetaDisplay *display,
screen->keys_grabbed = FALSE;
meta_screen_grab_keys (screen);
screen->ui = meta_ui_new ();
screen->ui = meta_ui_new (screen->display->xdisplay,
screen->xscreen);
screen->tab_popup = NULL;
screen->ws_popup = NULL;
screen->tile_preview_timeout_id = 0;
@ -806,7 +810,11 @@ meta_screen_free (MetaScreen *screen,
meta_display_grab (display);
meta_compositor_unmanage (screen->display->compositor);
if (screen->display->compositor)
{
meta_compositor_unmanage_screen (screen->display->compositor,
screen);
}
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
@ -837,7 +845,7 @@ meta_screen_free (MetaScreen *screen,
meta_stack_free (screen->stack);
meta_stack_tracker_free (screen->stack_tracker);
meta_error_trap_push (screen->display);
meta_error_trap_push_with_return (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",
@ -897,6 +905,28 @@ meta_screen_manage_all_windows (MetaScreen *screen)
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)
@ -1380,26 +1410,6 @@ 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)
@ -1408,7 +1418,261 @@ meta_screen_set_cursor (MetaScreen *screen,
return;
screen->current_cursor = cursor;
meta_screen_update_cursor (screen);
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);
}
void
meta_screen_tab_popup_create (MetaScreen *screen,
MetaTabList list_type,
MetaTabShowType show_type,
MetaWindow *initial_selection)
{
MetaTabEntry *entries;
GList *tab_list;
GList *tmp;
int len;
int i;
if (screen->tab_popup)
return;
tab_list = meta_display_get_tab_list (screen->display,
list_type,
screen,
screen->active_workspace);
len = g_list_length (tab_list);
entries = g_new (MetaTabEntry, len + 1);
entries[len].key = NULL;
entries[len].title = NULL;
entries[len].icon = NULL;
i = 0;
tmp = tab_list;
while (i < len)
{
MetaWindow *window;
MetaRectangle r;
window = tmp->data;
entries[i].key = (MetaTabEntryKey) window;
entries[i].title = window->title;
entries[i].icon = g_object_ref (window->icon);
entries[i].blank = FALSE;
entries[i].hidden = !meta_window_showing_on_its_workspace (window);
entries[i].demands_attention = window->wm_state_demands_attention;
if (show_type == META_TAB_SHOW_INSTANTLY ||
!entries[i].hidden ||
!meta_window_get_icon_geometry (window, &r))
meta_window_get_frame_rect (window, &r);
entries[i].rect = r;
/* Find inside of highlight rectangle to be used when window is
* outlined for tabbing. This should be the size of the
* east/west frame, and the size of the south frame, on those
* sides. On the top it should be the size of the south frame
* edge.
*/
#define OUTLINE_WIDTH 5
/* Top side */
if (!entries[i].hidden &&
window->frame && window->frame->bottom_height > 0 &&
window->frame->child_y >= window->frame->bottom_height)
entries[i].inner_rect.y = window->frame->bottom_height;
else
entries[i].inner_rect.y = OUTLINE_WIDTH;
/* Bottom side */
if (!entries[i].hidden &&
window->frame && window->frame->bottom_height != 0)
entries[i].inner_rect.height = r.height
- entries[i].inner_rect.y - window->frame->bottom_height;
else
entries[i].inner_rect.height = r.height
- entries[i].inner_rect.y - OUTLINE_WIDTH;
/* Left side */
if (!entries[i].hidden && window->frame && window->frame->child_x != 0)
entries[i].inner_rect.x = window->frame->child_x;
else
entries[i].inner_rect.x = OUTLINE_WIDTH;
/* Right side */
if (!entries[i].hidden &&
window->frame && window->frame->right_width != 0)
entries[i].inner_rect.width = r.width
- entries[i].inner_rect.x - window->frame->right_width;
else
entries[i].inner_rect.width = r.width
- entries[i].inner_rect.x - OUTLINE_WIDTH;
++i;
tmp = tmp->next;
}
if (!meta_prefs_get_no_tab_popup ())
screen->tab_popup = meta_ui_tab_popup_new (entries,
screen->number,
len,
5, /* FIXME */
TRUE);
for (i = 0; i < len; i++)
g_object_unref (entries[i].icon);
g_free (entries);
g_list_free (tab_list);
meta_ui_tab_popup_select (screen->tab_popup,
(MetaTabEntryKey) initial_selection);
if (show_type != META_TAB_SHOW_INSTANTLY)
meta_ui_tab_popup_set_showing (screen->tab_popup, TRUE);
}
void
meta_screen_tab_popup_forward (MetaScreen *screen)
{
g_return_if_fail (screen->tab_popup != NULL);
meta_ui_tab_popup_forward (screen->tab_popup);
}
void
meta_screen_tab_popup_backward (MetaScreen *screen)
{
g_return_if_fail (screen->tab_popup != NULL);
meta_ui_tab_popup_backward (screen->tab_popup);
}
MetaWindow *
meta_screen_tab_popup_get_selected (MetaScreen *screen)
{
g_return_val_if_fail (screen->tab_popup != NULL, NULL);
return (MetaWindow *) meta_ui_tab_popup_get_selected (screen->tab_popup);
}
void
meta_screen_tab_popup_destroy (MetaScreen *screen)
{
if (screen->tab_popup)
{
meta_ui_tab_popup_free (screen->tab_popup);
screen->tab_popup = NULL;
}
}
void
meta_screen_workspace_popup_create (MetaScreen *screen,
MetaWorkspace *initial_selection)
{
MetaTabEntry *entries;
int len;
int i;
MetaWorkspaceLayout layout;
int n_workspaces;
int current_workspace;
if (screen->ws_popup || meta_prefs_get_no_tab_popup ())
return;
current_workspace = meta_workspace_index (screen->active_workspace);
n_workspaces = meta_screen_get_n_workspaces (screen);
meta_screen_calc_workspace_layout (screen, n_workspaces,
current_workspace, &layout);
len = layout.grid_area;
entries = g_new (MetaTabEntry, len + 1);
entries[len].key = NULL;
entries[len].title = NULL;
entries[len].icon = NULL;
i = 0;
while (i < len)
{
if (layout.grid[i] >= 0)
{
MetaWorkspace *workspace;
workspace = meta_screen_get_workspace_by_index (screen,
layout.grid[i]);
entries[i].key = (MetaTabEntryKey) workspace;
entries[i].title = meta_workspace_get_name (workspace);
entries[i].icon = NULL;
entries[i].blank = FALSE;
g_assert (entries[i].title != NULL);
}
else
{
entries[i].key = NULL;
entries[i].title = NULL;
entries[i].icon = NULL;
entries[i].blank = TRUE;
}
entries[i].hidden = FALSE;
entries[i].demands_attention = FALSE;
++i;
}
screen->ws_popup = meta_ui_tab_popup_new (entries,
screen->number,
len,
layout.cols,
FALSE);
g_free (entries);
meta_screen_free_workspace_layout (&layout);
meta_ui_tab_popup_select (screen->ws_popup,
(MetaTabEntryKey) initial_selection);
meta_ui_tab_popup_set_showing (screen->ws_popup, TRUE);
}
void
meta_screen_workspace_popup_select (MetaScreen *screen,
MetaWorkspace *workspace)
{
g_return_if_fail (screen->ws_popup != NULL);
meta_ui_tab_popup_select (screen->ws_popup,
(MetaTabEntryKey) workspace);
}
MetaWorkspace *
meta_screen_workspace_popup_get_selected (MetaScreen *screen)
{
g_return_val_if_fail (screen->ws_popup != NULL, NULL);
return (MetaWorkspace *) meta_ui_tab_popup_get_selected (screen->ws_popup);
}
void
meta_screen_workspace_popup_destroy (MetaScreen *screen)
{
if (screen->ws_popup)
{
meta_ui_tab_popup_free (screen->ws_popup);
screen->ws_popup = NULL;
}
}
static gboolean
@ -1449,10 +1713,11 @@ 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,
window, &tile_rect, monitor);
screen, window, &tile_rect, monitor);
}
else
meta_compositor_hide_tile_preview (screen->display->compositor);
meta_compositor_hide_tile_preview (screen->display->compositor,
screen);
return FALSE;
}
@ -1488,7 +1753,8 @@ 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);
meta_compositor_hide_tile_preview (screen->display->compositor,
screen);
}
MetaWindow*
@ -1496,19 +1762,38 @@ meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one)
{
MetaWindow *window;
int x, y;
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;
if (not_this_one)
meta_topic (META_DEBUG_FOCUS,
"Focusing mouse window excluding %s\n", not_this_one->desc);
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
&x, &y, NULL);
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);
window = meta_stack_get_default_focus_window_at_point (screen->stack,
screen->active_workspace,
not_this_one,
x, y);
root_x_return,
root_y_return);
return window;
}
@ -1790,11 +2075,28 @@ meta_screen_get_current_monitor (MetaScreen *screen)
if (screen->display->monitor_cache_invalidated)
{
int x, y;
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;
meta_cursor_tracker_get_pointer (screen->cursor_tracker,
&x, &y, NULL);
meta_screen_get_current_monitor_for_pos (screen, 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);
}
return screen->last_monitor_index;
@ -2505,8 +2807,10 @@ on_monitors_changed (MetaMonitorManager *manager,
&changes);
}
meta_compositor_sync_screen_size (screen->display->compositor,
screen->rect.width, screen->rect.height);
if (screen->display->compositor)
meta_compositor_sync_screen_size (screen->display->compositor,
screen,
screen->rect.width, screen->rect.height);
/* Queue a resize on all the windows */
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
@ -3046,6 +3350,24 @@ 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)
{

View File

@ -1816,7 +1816,7 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
"and will have to be restarted manually next time "
"you log in."),
"240",
meta_get_display()->screen->screen_name,
meta_get_display()->active_screen->screen_name,
NULL, NULL, NULL,
None,
columns,

View File

@ -1245,8 +1245,10 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
meta_windows = g_list_prepend (meta_windows, window->wayland.meta_window);
}
meta_compositor_sync_stack (tracker->screen->display->compositor,
meta_windows);
if (tracker->screen->display->compositor)
meta_compositor_sync_stack (tracker->screen->display->compositor,
tracker->screen,
meta_windows);
g_list_free (meta_windows);
meta_screen_restacked (tracker->screen);

View File

@ -36,8 +36,6 @@
#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 || \
@ -1707,8 +1705,8 @@ get_default_focus_window (MetaStack *stack,
MetaWindow *topmost_in_group;
MetaWindow *topmost_overall;
MetaGroup *not_this_one_group;
GList *l;
GList *link;
transient_parent = NULL;
topmost_in_group = NULL;
topmost_overall = NULL;
@ -1720,49 +1718,49 @@ get_default_focus_window (MetaStack *stack,
stack_ensure_sorted (stack);
/* top of this layer is at the front of the list */
for (l = stack->sorted; l != NULL; l = l->next)
link = stack->sorted;
while (link)
{
MetaWindow *window = l->data;
MetaWindow *window = link->data;
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 (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 (transient_parent == NULL &&
meta_window_get_transient_for (not_this_one) == window)
transient_parent = window;
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 (topmost_in_group == NULL &&
not_this_one_group != NULL &&
not_this_one_group == meta_window_get_group (window))
topmost_in_group = 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_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.
*/
link = link->next;
}
if (transient_parent)

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