Compare commits

..

3 Commits

Author SHA1 Message Date
2210c30cba window-actor: Split into two subclasses of MetaSurfaceActor
The rendering logic before was somewhat complex. We had three independent
cases to take into account when doing rendering:

  * X11 compositor. In this case, we're a traditional X11 compositor,
    not a Wayland compositor. We use XCompositeNameWindowPixmap to get
    the backing pixmap for the window, and deal with the COMPOSITE
    extension messiness.

    In this case, meta_is_wayland_compositor() is FALSE.

  * Wayland clients. In this case, we're a Wayland compositor managing
    Wayland surfaces. The rendering for this is fairly straightforward,
    as Cogl handles most of the complexity with EGL and SHM buffers...
    Wayland clients give us the input and opaque regions through
    wl_surface.

    In this case, meta_is_wayland_compositor() is TRUE and
    priv->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND.

  * XWayland clients. In this case, we're a Wayland compositor, like
    above, and XWayland hands us Wayland surfaces. XWayland handles
    the COMPOSITE extension messiness for us, and hands us a buffer
    like any other Wayland client. We have to fetch the input and
    opaque regions from the X11 window ourselves.

    In this case, meta_is_wayland_compositor() is TRUE and
    priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11.

We now split the rendering logic into two subclasses, which are:

  * MetaSurfaceActorX11, which handles the X11 compositor case, in that
    it uses XCompositeNameWindowPixmap to get the backing pixmap, and
    deal with all the COMPOSITE extension messiness.

  * MetaSurfaceActorWayland, which handles the Wayland compositor case
    for both native Wayland clients and XWayland clients. XWayland handles
    COMPOSITE for us, and handles pushing a surface over through the
    xf86-video-wayland DDX.

Frame sync is still in MetaWindowActor, as it needs to work for both the
X11 compositor and XWayland client cases. When Wayland's video display
protocol lands, this will need to be significantly overhauled, as it would
have to work for any wl_surface, including subsurfaces, so we would need
surface-level discretion.

https://bugzilla.gnome.org/show_bug.cgi?id=720631
2014-02-19 10:24:38 -05:00
6b98ac3d1f window-actor: Kill off needs_pixmap
It's mostly equivalent to the case where we've already detached
the pixmap, *except* for the x11_size_changed case. We can simply
detach the pixmap at the time the window changes size, though.
2014-02-19 10:24:38 -05:00
13ddd366a9 window-actor: Don't queue a redraw when queueing a new pixmap
We guarantee ourselves that a valid pixmap will appear any time
that the window is painted. The window actor will be scheduled
for a repaint if it's added / removed from the scene graph, like
during construction, if the size changes, or if we receive damage,
which are the existing use cases where this function is called.

So, I can't see any reason that we queue a redraw in here.
2014-02-19 10:24:38 -05:00
128 changed files with 29719 additions and 6590 deletions

19
.gitignore vendored
View File

@ -78,12 +78,12 @@ src/stamp-mutter-marshal.h
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,10 +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

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

44
NEWS
View File

@ -1,47 +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]
* Make tile previews a compositor effect [Stefano, Florian; #665758]
* Misc. bug fixes and cleanups [Ryan, Giovanni, Jasper, Adel; #722530, #724257,
#724258, #720631, #724364, #724472]
Contributors:
Giovanni Campagna, Marek Chalupa, Stefano Facchini, Adel Gadllah,
Ryan Lortie, Florian Müllner, Jasper St. Pierre, Rico Tzschichholz
3.11.5
======
* Fix CSD titlebars being placed off-screen [Jasper; #719772]

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], [5])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@ -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
@ -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
])

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>

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,7 +6,6 @@ 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 \
@ -29,7 +28,11 @@ 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 = \
@ -37,20 +40,16 @@ mutter_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 \
xserver-protocol.c \
xserver-server-protocol.h
wayland_protocols = \
wayland/protocol/gtk-shell.xml \
wayland/protocol/xdg-shell.xml \
wayland/protocol/xserver.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 = \
core/above-tab-keycode.c \
core/async-getprop.c \
core/async-getprop.h \
core/barrier.c \
meta/barrier.h \
core/bell.c \
@ -105,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 \
@ -112,18 +112,25 @@ 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/edid-parse.c \
core/edid.h \
core/events.c \
core/events.h \
core/errors.c \
meta/errors.h \
core/frame.c \
core/frame.h \
ui/gradient.c \
meta/gradient.h \
core/group-private.h \
core/group-props.c \
core/group-props.h \
core/group.c \
meta/group.h \
core/iconcache.c \
core/iconcache.h \
core/keybindings.c \
core/keybindings-private.h \
core/main.c \
@ -146,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 \
@ -153,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 \
@ -169,31 +184,16 @@ libmutter_wayland_la_SOURCES = \
ui/metaaccellabel.h \
ui/resizepopup.c \
ui/resizepopup.h \
ui/tabpopup.c \
ui/tabpopup.h \
ui/tile-preview.c \
ui/tile-preview.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 \
wayland/meta-wayland.c \
wayland/meta-wayland.h \
wayland/meta-wayland-private.h \
wayland/meta-xwayland-private.h \
wayland/meta-xwayland.c \
@ -212,9 +212,7 @@ libmutter_wayland_la_SOURCES = \
wayland/meta-wayland-types.h \
wayland/meta-wayland-versions.h \
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h \
wayland/window-wayland.c \
wayland/window-wayland.h
wayland/meta-weston-launch.h
nodist_libmutter_wayland_la_SOURCES = \
$(mutter_built_sources)
@ -315,7 +313,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
@ -366,7 +364,6 @@ 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 \
@ -416,7 +413,9 @@ $(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
--c-generate-object-manager \
$(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

@ -19,10 +19,16 @@ struct _MetaCompositor
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;
};
@ -30,9 +36,10 @@ struct _MetaCompScreen
{
MetaScreen *screen;
ClutterActor *stage, *window_group, *top_window_group;
ClutterActor *stage, *window_group, *top_window_group, *overlay_group;
ClutterActor *background_actor;
GList *windows;
GHashTable *windows_by_xid;
Window output;
CoglOnscreen *onscreen;
@ -63,4 +70,6 @@ void meta_end_modal_for_plugin (MetaScreen *screen,
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 */

View File

@ -65,6 +65,7 @@
#include <meta/window.h>
#include "compositor-private.h"
#include <meta/compositor-mutter.h>
#include "xprops.h"
#include <meta/prefs.h>
#include <meta/main.h>
#include <meta/meta-background-actor.h>
@ -75,17 +76,14 @@
#include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */
#include "util-private.h"
#include "frame.h"
#include "meta-wayland-private.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-keyboard.h"
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
#include "wayland/meta-wayland-private.h"
static gboolean
is_modal (MetaDisplay *display)
{
return display->grab_op == META_GRAB_OP_COMPOSITOR;
}
/* #define DEBUG_TRACE g_print */
#define DEBUG_TRACE(X)
static inline gboolean
composite_at_least_version (MetaDisplay *display, int maj, int min)
@ -110,8 +108,13 @@ meta_finish_workspace_switch (MetaCompScreen *info)
for (l = info->windows; l; l = l->next)
meta_window_actor_sync_visibility (l->data);
/* Fix up stacking order. */
/*
* Fix up stacking order in case the plugin messed it up.
*/
sync_actor_stacking (info);
/* printf ("... FINISHED DESKTOP SWITCH\n"); */
}
void
@ -142,7 +145,15 @@ process_damage (MetaCompositor *compositor,
XDamageNotifyEvent *event,
MetaWindow *window)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
MetaWindowActor *window_actor;
if (window == NULL)
return;
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (window_actor == NULL)
return;
meta_window_actor_process_x11_damage (window_actor, event);
}
@ -305,36 +316,39 @@ meta_focus_stage_window (MetaScreen *screen,
if (!stage)
return;
window = clutter_x11_get_stage_window (stage);
if (!meta_is_wayland_compositor ())
{
window = clutter_x11_get_stage_window (stage);
if (window == None)
return;
if (window == None)
return;
meta_display_set_input_focus_xwindow (screen->display,
screen,
window,
timestamp);
meta_display_set_input_focus_xwindow (screen->display,
screen,
META_FOCUS_STAGE,
window,
timestamp);
}
else
{
meta_display_set_input_focus_xwindow (screen->display,
screen,
META_FOCUS_STAGE,
None,
timestamp);
}
}
gboolean
meta_stage_is_focused (MetaScreen *screen)
{
ClutterStage *stage;
Window window;
if (meta_is_wayland_compositor ())
return TRUE;
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
if (!stage)
return FALSE;
window = clutter_x11_get_stage_window (stage);
if (window == None)
return FALSE;
return (screen->display->focus_xwindow == window);
return (screen->display->focus_type == META_FOCUS_STAGE);
}
static gboolean
@ -347,6 +361,7 @@ begin_modal_x11 (MetaScreen *screen,
Display *xdpy = meta_display_get_xdisplay (display);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
Cursor cursor = None;
int result;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
@ -366,7 +381,7 @@ begin_modal_x11 (MetaScreen *screen,
META_VIRTUAL_CORE_POINTER_ID,
grab_window,
timestamp,
None,
cursor,
XIGrabModeAsync, XIGrabModeAsync,
False, /* owner_events */
&mask);
@ -410,6 +425,45 @@ begin_modal_x11 (MetaScreen *screen,
return FALSE;
}
static gboolean
begin_modal_wayland (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaWaylandCompositor *compositor;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
compositor = meta_wayland_compositor_get_default ();
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
goto fail;
pointer_grabbed = TRUE;
}
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
timestamp))
goto fail;
keyboard_grabbed = TRUE;
}
return TRUE;
fail:
if (pointer_grabbed)
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
if (keyboard_grabbed)
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
return FALSE;
}
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
@ -420,14 +474,19 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
* are significant differences in how we handle grabs that make it difficult to
* merge the two.
*/
MetaDisplay *display = meta_screen_get_display (screen);
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompositor *compositor = display->compositor;
gboolean ok;
if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE)
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
return FALSE;
if (!meta_is_wayland_compositor ())
if (!begin_modal_x11 (screen, plugin, options, timestamp))
return FALSE;
if (meta_is_wayland_compositor ())
ok = begin_modal_wayland (screen, plugin, options, timestamp);
else
ok = begin_modal_x11 (screen, plugin, options, timestamp);
if (!ok)
return FALSE;
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->grab_window = NULL;
@ -435,8 +494,7 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
display->grab_have_pointer = TRUE;
display->grab_have_keyboard = TRUE;
if (meta_is_wayland_compositor ())
meta_display_sync_wayland_input_focus (display);
compositor->modal_plugin = plugin;
return TRUE;
}
@ -446,10 +504,25 @@ meta_end_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
guint32 timestamp)
{
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
MetaCompositor *compositor = display->compositor;
g_return_if_fail (is_modal (display));
g_return_if_fail (compositor->modal_plugin == plugin);
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
timestamp);
}
else
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
}
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL;
@ -457,14 +530,25 @@ meta_end_modal_for_plugin (MetaScreen *screen,
display->grab_have_pointer = FALSE;
display->grab_have_keyboard = FALSE;
if (meta_is_wayland_compositor ())
compositor->modal_plugin = NULL;
}
/* This is used when reloading plugins to make sure we don't have
* a left-over modal grab for this screen.
*/
void
meta_check_end_modal (MetaScreen *screen)
{
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompositor *compositor = display->compositor;
if (compositor->modal_plugin &&
meta_plugin_get_screen (compositor->modal_plugin) == screen)
{
meta_display_sync_wayland_input_focus (display);
}
else
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
meta_end_modal_for_plugin (screen,
compositor->modal_plugin,
CurrentTime);
}
}
@ -667,25 +751,18 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor,
}
}
/**
* meta_shape_cow_for_window:
* @screen: A #MetaScreen
* @window: (allow-none): A #MetaWindow to shape the COW for
*
* Sets an bounding shape on the COW so that the given window
* is exposed. If @window is %NULL it clears the shape again.
*
* Used so we can unredirect windows, by shaping away the part
* of the COW, letting the raw window be seen through below.
/*
* Shapes the cow so that the given window is exposed,
* when metaWindow is NULL it clears the shape again
*/
static void
meta_shape_cow_for_window (MetaScreen *screen,
MetaWindow *window)
MetaWindow *metaWindow)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen));
if (window == NULL)
if (metaWindow == NULL)
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
else
{
@ -694,7 +771,7 @@ meta_shape_cow_for_window (MetaScreen *screen,
int width, height;
MetaRectangle rect;
meta_window_get_frame_rect (window, &rect);
meta_window_get_frame_rect (metaWindow, &rect);
window_bounds.x = rect.x;
window_bounds.y = rect.y;
@ -747,21 +824,35 @@ meta_compositor_add_window (MetaCompositor *compositor,
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
g_return_if_fail (info != NULL);
/* Window was already added previously, probably coming
* back from hiding */
if (window->compositor_private != NULL)
return;
meta_error_trap_push (display);
meta_window_actor_new (window);
sync_actor_stacking (info);
meta_error_trap_pop (display);
sync_actor_stacking (info);
}
void
meta_compositor_remove_window (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
MetaScreen *screen = meta_window_get_screen (window);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
MetaWindowActor *window_actor = NULL;
MetaScreen *screen;
MetaCompScreen *info;
DEBUG_TRACE ("meta_compositor_remove_window\n");
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (!window_actor)
return;
screen = meta_window_get_screen (window);
info = meta_screen_get_compositor_data (screen);
if (info->unredirected_window == window)
set_unredirected_window (info, NULL);
@ -774,7 +865,13 @@ meta_compositor_set_updates_frozen (MetaCompositor *compositor,
MetaWindow *window,
gboolean updates_frozen)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
MetaWindowActor *window_actor;
DEBUG_TRACE ("meta_compositor_set_updates_frozen\n");
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (!window_actor)
return;
meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
}
@ -783,7 +880,13 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
MetaWindow *window,
gboolean no_delay_frame)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
MetaWindowActor *window_actor;
DEBUG_TRACE ("meta_compositor_queue_frame_drawn\n");
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (!window_actor)
return;
meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
}
@ -834,43 +937,6 @@ meta_compositor_window_opacity_changed (MetaCompositor *compositor,
meta_window_actor_update_opacity (window_actor);
}
void
meta_compositor_window_surface_changed (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor;
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
if (!window_actor)
return;
meta_window_actor_update_surface (window_actor);
}
static gboolean
event_is_passive_button_grab (MetaDisplay *display,
XIDeviceEvent *device_event)
{
/* see display.c for which events are passive button
grabs (meta_display_grab_window_buttons() and
meta_display_handle_events())
we need to filter them here because normally they
would be sent to gtk+ (they are on gtk+ frame xwindow),
but we want to redirect them to clutter
*/
if (device_event->evtype != XI_ButtonPress)
return FALSE;
if (display->window_grab_modifiers == 0)
return FALSE;
if ((device_event->mods.effective & display->window_grab_modifiers) !=
display->window_grab_modifiers)
return FALSE;
return device_event->detail < 4;
}
/* Clutter makes the assumption that there is only one X window
* per stage, which is a valid assumption to make for a generic
* application toolkit. As such, it will ignore any events sent
@ -882,7 +948,6 @@ event_is_passive_button_grab (MetaDisplay *display,
*/
static void
maybe_spoof_event_as_stage_event (MetaCompScreen *info,
MetaWindow *window,
XEvent *event)
{
MetaDisplay *display = meta_screen_get_display (info->screen);
@ -891,30 +956,24 @@ maybe_spoof_event_as_stage_event (MetaCompScreen *info,
event->xcookie.extension == display->xinput_opcode)
{
XIEvent *input_event = (XIEvent *) event->xcookie.data;
XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event);
switch (input_event->evtype)
{
case XI_Motion:
case XI_ButtonPress:
case XI_ButtonRelease:
/* If this is a window frame, and we think GTK+ needs to handle the event,
let GTK+ handle it without mangling */
if (window && window->frame && device_event->event == window->frame->xwindow &&
(meta_grab_op_is_clicking (display->grab_op) ||
(display->grab_op == META_GRAB_OP_NONE && !event_is_passive_button_grab (display, device_event))))
break;
case XI_KeyPress:
case XI_KeyRelease:
{
XIDeviceEvent *device_event = ((XIDeviceEvent *) input_event);
/* If this is a GTK+ widget, like a window menu, let GTK+ handle
* it as-is without mangling. */
if (meta_ui_window_is_widget (info->screen->ui, device_event->event))
break;
device_event->event = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
device_event->event_x = device_event->root_x;
device_event->event_y = device_event->root_y;
}
break;
default:
break;
@ -934,26 +993,53 @@ meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event,
MetaWindow *window)
{
MetaDisplay *display = compositor->display;
MetaScreen *screen = display->screens->data;
MetaCompScreen *info;
info = meta_screen_get_compositor_data (screen);
if (is_modal (display) && is_grabbed_event (compositor->display, event))
if (compositor->modal_plugin && is_grabbed_event (compositor->display, event))
{
meta_plugin_manager_xevent_filter (info->plugin_mgr, event);
_meta_plugin_xevent_filter (compositor->modal_plugin, event);
/* We always consume events even if the plugin says it didn't handle them;
* exclusive is exclusive */
return TRUE;
}
if (!meta_is_wayland_compositor ())
maybe_spoof_event_as_stage_event (info, window, event);
if (window)
{
MetaCompScreen *info;
MetaScreen *screen;
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
return TRUE;
screen = meta_window_get_screen (window);
info = meta_screen_get_compositor_data (screen);
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
{
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
return TRUE;
}
}
else
{
GSList *l;
l = meta_display_get_screens (compositor->display);
while (l)
{
MetaScreen *screen = l->data;
MetaCompScreen *info;
info = meta_screen_get_compositor_data (screen);
maybe_spoof_event_as_stage_event (info, event);
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
{
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
return TRUE;
}
l = l->next;
}
}
if (!meta_is_wayland_compositor () &&
event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
@ -967,6 +1053,7 @@ meta_compositor_process_event (MetaCompositor *compositor,
window = meta_display_lookup_x_window (compositor->display, xwin);
}
DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
process_damage (compositor, (XDamageNotifyEvent *) event, window);
}
@ -988,7 +1075,11 @@ meta_compositor_filter_keybinding (MetaCompositor *compositor,
MetaKeyBinding *binding)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding);
if (info->plugin_mgr)
return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding);
return FALSE;
}
void
@ -997,7 +1088,11 @@ meta_compositor_show_window (MetaCompositor *compositor,
MetaCompEffect effect)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
meta_window_actor_show (window_actor, effect);
DEBUG_TRACE ("meta_compositor_show_window\n");
if (!window_actor)
return;
meta_window_actor_show (window_actor, effect);
}
void
@ -1006,6 +1101,10 @@ meta_compositor_hide_window (MetaCompositor *compositor,
MetaCompEffect effect)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_hide_window\n");
if (!window_actor)
return;
meta_window_actor_hide (window_actor, effect);
}
@ -1016,6 +1115,10 @@ meta_compositor_maximize_window (MetaCompositor *compositor,
MetaRectangle *new_rect)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_maximize_window\n");
if (!window_actor)
return;
meta_window_actor_maximize (window_actor, old_rect, new_rect);
}
@ -1026,6 +1129,10 @@ meta_compositor_unmaximize_window (MetaCompositor *compositor,
MetaRectangle *new_rect)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
DEBUG_TRACE ("meta_compositor_unmaximize_window\n");
if (!window_actor)
return;
meta_window_actor_unmaximize (window_actor, old_rect, new_rect);
}
@ -1043,14 +1150,18 @@ meta_compositor_switch_workspace (MetaCompositor *compositor,
to_indx = meta_workspace_index (to);
from_indx = meta_workspace_index (from);
DEBUG_TRACE ("meta_compositor_switch_workspace\n");
if (!info) /* During startup before manage_screen() */
return;
info->switch_workspace_in_progress++;
if (!meta_plugin_manager_switch_workspace (info->plugin_mgr,
from_indx, to_indx,
direction))
if (!info->plugin_mgr ||
!meta_plugin_manager_switch_workspace (info->plugin_mgr,
from_indx,
to_indx,
direction))
{
info->switch_workspace_in_progress--;
@ -1159,6 +1270,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
GList *old_stack;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
DEBUG_TRACE ("meta_compositor_sync_stack\n");
/* This is painful because hidden windows that we are in the process
* of animating out of existence. They'll be at the bottom of the
* stack of X windows, but we want to leave them in their old position
@ -1247,6 +1360,15 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor,
gboolean did_placement)
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
MetaScreen *screen = meta_window_get_screen (window);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
DEBUG_TRACE ("meta_compositor_sync_window_geometry\n");
g_return_if_fail (info);
if (!window_actor)
return;
meta_window_actor_sync_actor_geometry (window_actor, did_placement);
}
@ -1278,6 +1400,7 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
Display *xdisplay;
Window xwin;
DEBUG_TRACE ("meta_compositor_sync_screen_size\n");
g_return_if_fail (info);
xdisplay = meta_display_get_xdisplay (display);
@ -1572,23 +1695,3 @@ meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
else
return monotonic_time + compositor->server_time_offset;
}
void
meta_compositor_show_tile_preview (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
meta_plugin_manager_show_tile_preview (info->plugin_mgr,
window, tile_rect, tile_monitor_number);
}
void
meta_compositor_hide_tile_preview (MetaCompositor *compositor,
MetaScreen *screen)
{
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
meta_plugin_manager_hide_tile_preview (info->plugin_mgr);
}

View File

@ -100,9 +100,7 @@ meta_plugin_manager_new (MetaScreen *screen)
plugin_mgr = g_new0 (MetaPluginManager, 1);
plugin_mgr->screen = screen;
plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL);
_meta_plugin_set_screen (plugin, screen);
plugin_mgr->plugin = plugin = g_object_new (plugin_type, "screen", screen, NULL);
klass = META_PLUGIN_GET_CLASS (plugin);
@ -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;
@ -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);
@ -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);
}
@ -315,44 +324,3 @@ meta_plugin_manager_confirm_display_change (MetaPluginManager *plugin_mgr)
else
return meta_plugin_complete_display_change (plugin, TRUE);
}
gboolean
meta_plugin_manager_show_tile_preview (MetaPluginManager *plugin_mgr,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
if (klass->show_tile_preview)
{
klass->show_tile_preview (plugin, window, tile_rect, tile_monitor_number);
return TRUE;
}
return FALSE;
}
gboolean
meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
MetaDisplay *display = meta_screen_get_display (plugin_mgr->screen);
if (display->display_opening)
return FALSE;
if (klass->hide_tile_preview)
{
klass->hide_tile_preview (plugin);
return TRUE;
}
return FALSE;
}

View File

@ -75,9 +75,4 @@ gboolean _meta_plugin_xevent_filter (MetaPlugin *plugin,
void meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr);
gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr);
#endif

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>
@ -47,15 +46,91 @@ G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
#define META_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate))
enum
{
PROP_0,
PROP_SCREEN,
PROP_DEBUG_MODE,
};
struct _MetaPluginPrivate
{
MetaScreen *screen;
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)
@ -101,8 +207,15 @@ void
meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
MetaScreen *screen = priv->screen;
if (priv->running-- < 0)
{
g_warning ("Error in running effect accounting, adjusting.");
priv->running = 0;
}
meta_switch_workspace_completed (screen);
}
@ -111,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);
}
@ -205,7 +338,9 @@ meta_plugin_end_modal (MetaPlugin *plugin,
* 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
*/
@ -217,15 +352,6 @@ meta_plugin_get_screen (MetaPlugin *plugin)
return priv->screen;
}
void
_meta_plugin_set_screen (MetaPlugin *plugin,
MetaScreen *screen)
{
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
priv->screen = screen;
}
void
meta_plugin_complete_display_change (MetaPlugin *plugin,
gboolean ok)

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
@ -83,21 +65,8 @@ meta_surface_actor_wayland_pre_paint (MetaSurfaceActor *actor)
static gboolean
meta_surface_actor_wayland_is_argb32 (MetaSurfaceActor *actor)
{
MetaShapedTexture *stex = meta_surface_actor_get_texture (actor);
CoglTexture *texture = meta_shaped_texture_get_texture (stex);
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 ();
}
/* XXX -- look at the SHM buffer format. */
return TRUE;
}
static gboolean
@ -128,14 +97,6 @@ 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_class_init (MetaSurfaceActorWaylandClass *klass)
{
@ -149,16 +110,11 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
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;
}
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 *
@ -181,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

@ -387,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)
{
@ -411,8 +403,6 @@ meta_surface_actor_x11_class_init (MetaSurfaceActorX11Class *klass)
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
@ -424,49 +414,26 @@ meta_surface_actor_x11_init (MetaSurfaceActorX11 *self)
priv->last_height = -1;
}
static void
create_damage (MetaSurfaceActorX11 *self)
{
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
Display *xdisplay = meta_display_get_xdisplay (priv->display);
Window xwindow = meta_window_get_toplevel_xwindow (priv->window);
priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox);
}
static void
window_decorated_notify (MetaWindow *window,
GParamSpec *pspec,
gpointer user_data)
{
MetaSurfaceActorX11 *self = META_SURFACE_ACTOR_X11 (user_data);
free_damage (self);
create_damage (self);
}
MetaSurfaceActor *
meta_surface_actor_x11_new (MetaWindow *window)
{
MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
MetaDisplay *display = meta_window_get_display (window);
Display *xdisplay = meta_display_get_xdisplay (display);
Window xwindow = meta_window_get_toplevel_xwindow (window);
g_assert (!meta_is_wayland_compositor ());
priv->window = window;
priv->display = display;
create_damage (self);
g_signal_connect_object (priv->window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportBoundingBox);
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"
@ -25,8 +26,8 @@ struct _MetaSurfaceActorPrivate
cairo_region_t *input_region;
/* Freeze/thaw accounting */
guint freeze_count;
guint needs_damage_all : 1;
guint frozen : 1;
};
static void cullable_iface_init (MetaCullableInterface *iface);
@ -34,14 +35,6 @@ static void cullable_iface_init (MetaCullableInterface *iface);
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
enum {
REPAINT_SCHEDULED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL];
gboolean
meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self,
cairo_rectangle_int_t *unobscured_bounds)
@ -121,13 +114,6 @@ meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
object_class->dispose = meta_surface_actor_dispose;
actor_class->pick = meta_surface_actor_pick;
signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
}
@ -178,14 +164,12 @@ meta_surface_actor_get_texture (MetaSurfaceActor *self)
return self->priv->texture;
}
void
gboolean
meta_surface_actor_update_area (MetaSurfaceActor *self,
int x, int y, int width, int height)
{
MetaSurfaceActorPrivate *priv = self->priv;
if (meta_shaped_texture_update_area (priv->texture, x, y, width, height))
g_signal_emit (self, signals[REPAINT_SCHEDULED], 0);
return meta_shaped_texture_update_area (priv->texture, x, y, width, height);
}
gboolean
@ -222,7 +206,7 @@ static gboolean
is_frozen (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
return priv->frozen;
return (priv->freeze_count > 0);
}
void
@ -273,19 +257,31 @@ meta_surface_actor_is_visible (MetaSurfaceActor *self)
}
void
meta_surface_actor_set_frozen (MetaSurfaceActor *self,
gboolean frozen)
meta_surface_actor_freeze (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
priv->frozen = frozen;
priv->freeze_count ++;
}
if (!frozen && priv->needs_damage_all)
void
meta_surface_actor_thaw (MetaSurfaceActor *self)
{
MetaSurfaceActorPrivate *priv = self->priv;
if (priv->freeze_count == 0)
{
/* Since we ignore damage events while a window is frozen for certain effects
* we may need to issue an update_area() covering the whole pixmap if we
* don't know what real damage has happened. */
g_critical ("Error in freeze/thaw accounting.");
return;
}
priv->freeze_count --;
/* Since we ignore damage events while a window is frozen for certain effects
* we may need to issue an update_area() covering the whole pixmap if we
* don't know what real damage has happened. */
if (priv->needs_damage_all)
{
meta_surface_actor_process_damage (self, 0, 0,
clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)),
clutter_actor_get_height (CLUTTER_ACTOR (priv->texture)));
@ -293,6 +289,12 @@ meta_surface_actor_set_frozen (MetaSurfaceActor *self,
}
}
gboolean
meta_surface_actor_is_frozen (MetaSurfaceActor *self)
{
return is_frozen (self);
}
gboolean
meta_surface_actor_should_unredirect (MetaSurfaceActor *self)
{
@ -311,9 +313,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
@ -36,8 +35,6 @@ struct _MetaSurfaceActorClass
void (* set_unredirected) (MetaSurfaceActor *actor,
gboolean unredirected);
gboolean (* is_unredirected) (MetaSurfaceActor *actor);
MetaWindow *(* get_window) (MetaSurfaceActor *actor);
};
struct _MetaSurfaceActor
@ -53,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,
@ -64,8 +60,8 @@ void meta_surface_actor_set_input_region (MetaSurfaceActor *self,
void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
cairo_region_t *region);
void meta_surface_actor_update_area (MetaSurfaceActor *actor,
int x, int y, int width, int height);
gboolean meta_surface_actor_update_area (MetaSurfaceActor *actor,
int x, int y, int width, int height);
void meta_surface_actor_process_damage (MetaSurfaceActor *actor,
int x, int y, int width, int height);
@ -73,8 +69,9 @@ void meta_surface_actor_pre_paint (MetaSurfaceActor *actor);
gboolean meta_surface_actor_is_argb32 (MetaSurfaceActor *actor);
gboolean meta_surface_actor_is_visible (MetaSurfaceActor *actor);
void meta_surface_actor_set_frozen (MetaSurfaceActor *actor,
gboolean frozen);
void meta_surface_actor_freeze (MetaSurfaceActor *actor);
void meta_surface_actor_thaw (MetaSurfaceActor *actor);
gboolean meta_surface_actor_is_frozen (MetaSurfaceActor *actor);
gboolean meta_surface_actor_should_unredirect (MetaSurfaceActor *actor);
void meta_surface_actor_set_unredirected (MetaSurfaceActor *actor,

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"
@ -60,6 +63,5 @@ void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);
MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
void meta_window_actor_update_surface (MetaWindowActor *self);
#endif /* META_WINDOW_ACTOR_PRIVATE_H */

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,14 +28,13 @@
#include "meta-window-actor-private.h"
#include "meta-texture-rectangle.h"
#include "region-utils.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;
@ -68,9 +68,6 @@ struct _MetaWindowActorPrivate
guint send_frame_messages_timer;
gint64 frame_drawn_time;
guint repaint_scheduled_id;
guint allocation_changed_id;
/*
* These need to be counters rather than flags, since more plugins
* can implement same effect; the practicality of stacking effects
@ -84,10 +81,10 @@ struct _MetaWindowActorPrivate
/* List of FrameData for recent frames */
GList *frames;
guint freeze_count;
guint visible : 1;
guint disposed : 1;
guint redecorating : 1;
/* If set, the client needs to be sent a _NET_WM_FRAME_DRAWN
* client message using the most recent frame in ->frames */
@ -222,6 +219,26 @@ meta_window_actor_init (MetaWindowActor *self)
priv->shadow_class = NULL;
}
static void
window_decorated_notify (MetaWindow *mw,
GParamSpec *arg1,
gpointer data)
{
MetaWindowActor *self = META_WINDOW_ACTOR (data);
MetaWindowActorPrivate *priv = self->priv;
/*
* Basically, we have to reconstruct the the internals of this object
* from scratch, as everything has changed.
*/
priv->redecorating = TRUE;
/*
* Recreate the contents.
*/
meta_window_actor_constructed (G_OBJECT (self));
}
static void
window_appears_focused_notify (MetaWindow *mw,
GParamSpec *arg1,
@ -240,29 +257,11 @@ surface_allocation_changed_notify (ClutterActor *actor,
meta_window_actor_update_shape (self);
}
static void
surface_repaint_scheduled (MetaSurfaceActor *actor,
gpointer user_data)
{
MetaWindowActor *self = META_WINDOW_ACTOR (user_data);
MetaWindowActorPrivate *priv = self->priv;
priv->repaint_scheduled = TRUE;
}
static gboolean
is_argb32 (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
/* assume we're argb until we get the window (because
in practice we're drawing nothing, so we're fully
transparent)
*/
if (priv->surface)
return meta_surface_actor_is_argb32 (priv->surface);
else
return TRUE;
return meta_surface_actor_is_argb32 (priv->surface);
}
static gboolean
@ -278,19 +277,14 @@ static gboolean
is_frozen (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
return priv->surface == NULL || priv->freeze_count > 0;
return meta_surface_actor_is_frozen (priv->surface);
}
static void
meta_window_actor_freeze (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->freeze_count == 0 && priv->surface)
meta_surface_actor_set_frozen (priv->surface, TRUE);
priv->freeze_count ++;
meta_surface_actor_freeze (priv->surface);
}
static void
@ -298,16 +292,11 @@ meta_window_actor_thaw (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->freeze_count <= 0)
g_error ("Error in freeze/thaw accounting");
meta_surface_actor_thaw (priv->surface);
priv->freeze_count--;
if (priv->freeze_count > 0)
if (is_frozen (self))
return;
if (priv->surface)
meta_surface_actor_set_frozen (priv->surface, FALSE);
/* We sometimes ignore moves and resizes on frozen windows */
meta_window_actor_sync_actor_geometry (self, FALSE);
@ -316,58 +305,6 @@ meta_window_actor_thaw (MetaWindowActor *self)
meta_window_actor_handle_updates (self);
}
static void
set_surface (MetaWindowActor *self,
MetaSurfaceActor *surface)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->surface)
{
g_signal_handler_disconnect (priv->surface, priv->repaint_scheduled_id);
priv->repaint_scheduled_id = 0;
g_signal_handler_disconnect (priv->surface, priv->allocation_changed_id);
priv->allocation_changed_id = 0;
clutter_actor_remove_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
g_object_unref (priv->surface);
}
priv->surface = surface;
if (priv->surface)
{
g_object_ref_sink (priv->surface);
priv->repaint_scheduled_id = g_signal_connect (priv->surface, "repaint-scheduled",
G_CALLBACK (surface_repaint_scheduled), self);
priv->allocation_changed_id = g_signal_connect (priv->surface, "allocation-changed",
G_CALLBACK (surface_allocation_changed_notify), self);
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
/* If the previous surface actor was frozen, start out
* frozen as well... */
meta_surface_actor_set_frozen (priv->surface, priv->freeze_count > 0);
meta_window_actor_update_shape (self);
}
}
void
meta_window_actor_update_surface (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
MetaSurfaceActor *surface_actor;
if (window->surface)
surface_actor = window->surface->surface_actor;
else if (!meta_is_wayland_compositor ())
surface_actor = meta_surface_actor_x11_new (window);
else
surface_actor = NULL;
set_surface (self, surface_actor);
}
static void
meta_window_actor_constructed (GObject *object)
{
@ -377,7 +314,20 @@ meta_window_actor_constructed (GObject *object)
priv->screen = window->screen;
meta_window_actor_update_surface (self);
if (!priv->surface)
{
if (window->surface)
priv->surface = window->surface->surface_actor;
else
priv->surface = meta_surface_actor_x11_new (window);
g_object_ref_sink (priv->surface);
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface));
g_signal_connect_object (priv->surface, "allocation-changed",
G_CALLBACK (surface_allocation_changed_notify), self, 0);
meta_window_actor_update_shape (self);
}
meta_window_actor_update_opacity (self);
@ -420,7 +370,10 @@ meta_window_actor_dispose (GObject *object)
g_clear_object (&priv->window);
set_surface (self, NULL);
/*
* Release the extra reference we took on the actor.
*/
g_clear_object (&priv->surface);
G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object);
}
@ -449,6 +402,9 @@ meta_window_actor_set_property (GObject *object,
{
case PROP_META_WINDOW:
priv->window = g_value_dup_object (value);
g_signal_connect_object (priv->window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
g_signal_connect_object (priv->window, "notify::appears-focused",
G_CALLBACK (window_appears_focused_notify), self, 0);
break;
@ -670,12 +626,6 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
meta_window_actor_get_shape_bounds (self, &bounds);
if (priv->surface)
{
if (meta_surface_actor_get_unobscured_bounds (priv->surface, &unobscured_bounds))
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
}
if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
{
cairo_rectangle_int_t shadow_bounds;
@ -691,6 +641,9 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
}
if (meta_surface_actor_get_unobscured_bounds (priv->surface, &unobscured_bounds))
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
origin.x = bounds.x;
origin.y = bounds.y;
origin.z = 0.0f;
@ -714,7 +667,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;
@ -785,26 +738,21 @@ meta_window_actor_get_meta_window (MetaWindowActor *self)
* meta_window_actor_get_texture:
* @self: a #MetaWindowActor
*
* Gets the ClutterActor that is used to display the contents of the window,
* or NULL if no texture is shown yet, because the window is not mapped.
* Gets the ClutterActor that is used to display the contents of the window
*
* Return value: (transfer none): the #ClutterActor for the contents
*/
ClutterActor *
meta_window_actor_get_texture (MetaWindowActor *self)
{
if (self->priv->surface)
return CLUTTER_ACTOR (meta_surface_actor_get_texture (self->priv->surface));
else
return NULL;
return CLUTTER_ACTOR (meta_surface_actor_get_texture (self->priv->surface));
}
/**
* meta_window_actor_get_surface:
* @self: a #MetaWindowActor
*
* Gets the MetaSurfaceActor that draws the content of this window,
* or NULL if there is no surface yet associated with this window.
* Gets the MetaSurfaceActor that draws the content of this window
*
* Return value: (transfer none): the #MetaSurfaceActor for the contents
*/
@ -903,12 +851,7 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
if (!priv->repaint_scheduled)
{
gboolean is_obscured;
if (priv->surface)
is_obscured = meta_surface_actor_is_obscured (priv->surface);
else
is_obscured = FALSE;
gboolean is_obscured = meta_surface_actor_is_obscured (priv->surface);
/* A frame was marked by the client without actually doing any
* damage or any unobscured, or while we had the window frozen
@ -924,12 +867,9 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
}
else
{
if (priv->surface)
{
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip);
priv->repaint_scheduled = TRUE;
}
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (priv->surface), &clip);
priv->repaint_scheduled = TRUE;
}
}
}
@ -968,6 +908,9 @@ start_simple_effect (MetaWindowActor *self,
gint *counter = NULL;
gboolean use_freeze_thaw = FALSE;
if (!info->plugin_mgr)
return FALSE;
switch (event)
{
case META_PLUGIN_MINIMIZE:
@ -1099,10 +1042,7 @@ gboolean
meta_window_actor_should_unredirect (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->surface)
return meta_surface_actor_should_unredirect (priv->surface);
else
return FALSE;
return meta_surface_actor_should_unredirect (priv->surface);
}
void
@ -1110,8 +1050,6 @@ meta_window_actor_set_unredirected (MetaWindowActor *self,
gboolean unredirected)
{
MetaWindowActorPrivate *priv = self->priv;
g_assert(priv->surface); /* because otherwise should_unredirect() is FALSE */
meta_surface_actor_set_unredirected (priv->surface, unredirected);
}
@ -1229,11 +1167,13 @@ meta_window_actor_show (MetaWindowActor *self,
g_assert_not_reached();
}
if (info->switch_workspace_in_progress ||
if (priv->redecorating ||
info->switch_workspace_in_progress ||
event == 0 ||
!start_simple_effect (self, event))
{
clutter_actor_show (CLUTTER_ACTOR (self));
priv->redecorating = FALSE;
}
}
@ -1296,7 +1236,8 @@ meta_window_actor_maximize (MetaWindowActor *self,
self->priv->maximize_in_progress++;
meta_window_actor_freeze (self);
if (!meta_plugin_manager_event_maximize (info->plugin_mgr,
if (!info->plugin_mgr ||
!meta_plugin_manager_event_maximize (info->plugin_mgr,
self,
META_PLUGIN_MAXIMIZE,
new_rect->x, new_rect->y,
@ -1324,7 +1265,8 @@ meta_window_actor_unmaximize (MetaWindowActor *self,
self->priv->unmaximize_in_progress++;
meta_window_actor_freeze (self);
if (!meta_plugin_manager_event_maximize (info->plugin_mgr,
if (!info->plugin_mgr ||
!meta_plugin_manager_event_maximize (info->plugin_mgr,
self,
META_PLUGIN_UNMAXIMIZE,
new_rect->x, new_rect->y,
@ -1466,7 +1408,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);
}
@ -1556,12 +1497,11 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->surface)
meta_surface_actor_process_damage (priv->surface,
event->area.x,
event->area.y,
event->area.width,
event->area.height);
meta_surface_actor_process_damage (priv->surface,
event->area.x,
event->area.y,
event->area.width,
event->area.height);
}
void
@ -1709,25 +1649,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)
{
@ -1738,11 +1675,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;
@ -1753,43 +1690,34 @@ 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;
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)
if (priv->window->frame != NULL && priv->window->input_region != NULL)
{
region = meta_frame_get_frame_bounds (priv->window->frame);
cairo_region_subtract_rectangle (region, client_area);
/* input_region 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);
cairo_region_translate (region, -client_area->x, -client_area->y);
cairo_region_union (region, priv->window->input_region);
cairo_region_translate (region, client_area->x, client_area->y);
}
else if (priv->window->shape_region != NULL ||
priv->window->input_region != NULL)
else if (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);
region = cairo_region_reference (priv->window->input_region);
}
else
{
/* If we don't have a shape on the server, that means that
* we have an implicit shape of one rectangle covering the
* entire window. */
region = cairo_region_create_rectangle (&client_area);
region = cairo_region_create_rectangle (client_area);
}
meta_surface_actor_set_input_region (priv->surface, region);
@ -1805,9 +1733,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
@ -1820,7 +1748,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)
@ -1836,15 +1764,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);
}
@ -2064,8 +2004,7 @@ meta_window_actor_update_opacity (MetaWindowActor *self)
MetaWindowActorPrivate *priv = self->priv;
MetaWindow *window = priv->window;
if (priv->surface)
clutter_actor_set_opacity (CLUTTER_ACTOR (priv->surface), window->opacity);
clutter_actor_set_opacity (CLUTTER_ACTOR (self->priv->surface), window->opacity);
}
void

View File

@ -39,7 +39,6 @@
#define SWITCH_TIMEOUT 500
#define ACTOR_DATA_KEY "MCCP-Default-actor-data"
#define SCREEN_TILE_PREVIEW_DATA_KEY "MCCP-Default-screen-tile-preview-data"
#define META_TYPE_DEFAULT_PLUGIN (meta_default_plugin_get_type ())
#define META_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEFAULT_PLUGIN, MetaDefaultPlugin))
@ -68,7 +67,6 @@ struct _MetaDefaultPluginClass
};
static GQuark actor_data_quark = 0;
static GQuark screen_tile_preview_data_quark = 0;
static void start (MetaPlugin *plugin);
static void minimize (MetaPlugin *plugin,
@ -99,12 +97,6 @@ static void kill_window_effects (MetaPlugin *plugin,
MetaWindowActor *actor);
static void kill_switch_workspace (MetaPlugin *plugin);
static void show_tile_preview (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
static void hide_tile_preview (MetaPlugin *plugin);
static void confirm_display_change (MetaPlugin *plugin);
static const MetaPluginInfo * plugin_info (MetaPlugin *plugin);
@ -151,15 +143,6 @@ typedef struct
} EffectCompleteData;
typedef struct _ScreenTilePreview
{
ClutterActor *actor;
GdkRGBA *preview_color;
MetaRectangle tile_rect;
} ScreenTilePreview;
static void
meta_default_plugin_dispose (GObject *object)
{
@ -220,8 +203,6 @@ meta_default_plugin_class_init (MetaDefaultPluginClass *klass)
plugin_class->unmaximize = unmaximize;
plugin_class->destroy = destroy;
plugin_class->switch_workspace = switch_workspace;
plugin_class->show_tile_preview = show_tile_preview;
plugin_class->hide_tile_preview = hide_tile_preview;
plugin_class->plugin_info = plugin_info;
plugin_class->kill_window_effects = kill_window_effects;
plugin_class->kill_switch_workspace = kill_switch_workspace;
@ -768,82 +749,6 @@ destroy (MetaPlugin *plugin, MetaWindowActor *window_actor)
meta_plugin_destroy_completed (plugin, window_actor);
}
/*
* Tile preview private data accessor
*/
static void
free_screen_tile_preview (gpointer data)
{
ScreenTilePreview *preview = data;
if (G_LIKELY (preview != NULL)) {
clutter_actor_destroy (preview->actor);
g_slice_free (ScreenTilePreview, preview);
}
}
static ScreenTilePreview *
get_screen_tile_preview (MetaScreen *screen)
{
ScreenTilePreview *preview = g_object_get_qdata (G_OBJECT (screen), screen_tile_preview_data_quark);
if (G_UNLIKELY (screen_tile_preview_data_quark == 0))
screen_tile_preview_data_quark = g_quark_from_static_string (SCREEN_TILE_PREVIEW_DATA_KEY);
if (G_UNLIKELY (!preview))
{
preview = g_slice_new0 (ScreenTilePreview);
preview->actor = clutter_actor_new ();
clutter_actor_set_background_color (preview->actor, CLUTTER_COLOR_Blue);
clutter_actor_set_opacity (preview->actor, 100);
clutter_actor_add_child (meta_get_window_group_for_screen (screen), preview->actor);
g_object_set_qdata_full (G_OBJECT (screen),
screen_tile_preview_data_quark, preview,
free_screen_tile_preview);
}
return preview;
}
static void
show_tile_preview (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number)
{
MetaScreen *screen = meta_plugin_get_screen (plugin);
ScreenTilePreview *preview = get_screen_tile_preview (screen);
ClutterActor *window_actor;
if (CLUTTER_ACTOR_IS_VISIBLE (preview->actor)
&& preview->tile_rect.x == tile_rect->x
&& preview->tile_rect.y == tile_rect->y
&& preview->tile_rect.width == tile_rect->width
&& preview->tile_rect.height == tile_rect->height)
return; /* nothing to do */
clutter_actor_set_position (preview->actor, tile_rect->x, tile_rect->y);
clutter_actor_set_size (preview->actor, tile_rect->width, tile_rect->height);
clutter_actor_show (preview->actor);
window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
clutter_actor_lower (preview->actor, window_actor);
preview->tile_rect = *tile_rect;
}
static void
hide_tile_preview (MetaPlugin *plugin)
{
MetaScreen *screen = meta_plugin_get_screen (plugin);
ScreenTilePreview *preview = get_screen_tile_preview (screen);
clutter_actor_hide (preview->actor);
}
static void
kill_switch_workspace (MetaPlugin *plugin)
{

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
@ -82,7 +164,12 @@ bell_flash_fullscreen (MetaDisplay *display,
{
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
if (screen)
meta_compositor_flash_screen (display->compositor, screen);
{
if (display->compositor)
meta_compositor_flash_screen (display->compositor, screen);
else
bell_flash_screen (display, screen);
}
}
else
{
@ -90,7 +177,10 @@ bell_flash_fullscreen (MetaDisplay *display,
while (screen_list)
{
screen = (MetaScreen *) screen_list->data;
meta_compositor_flash_screen (display->compositor, screen);
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

@ -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
@ -718,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

@ -84,6 +84,14 @@ typedef enum {
META_TILE_MAXIMIZED
} MetaTileMode;
typedef enum {
META_FOCUS_NONE = 0,
META_FOCUS_X_CLIENT = 1,
META_FOCUS_WAYLAND_CLIENT = 2,
META_FOCUS_NO_FOCUS_WINDOW = 3,
META_FOCUS_STAGE = 4
} MetaFocusType;
struct _MetaDisplay
{
GObject parent_instance;
@ -117,6 +125,7 @@ struct _MetaDisplay
* like the no_focus_window or the stage X window. */
Window focus_xwindow;
gulong focus_serial;
MetaFocusType focus_type;
/* last timestamp passed to XSetInputFocus */
guint32 last_focus_time;
@ -145,6 +154,8 @@ struct _MetaDisplay
* multiple events with the same serial.
*/
guint focused_by_us : 1;
guint static_gravity_works : 1;
/*< private-ish >*/
guint error_trap_synced_at_last_pop : 1;
@ -213,6 +224,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;
@ -230,8 +242,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;
@ -454,9 +466,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,
@ -484,21 +493,10 @@ gboolean meta_display_process_barrier_event (MetaDisplay *display,
XIEvent *event);
#endif /* HAVE_XI23 */
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
MetaScreen *screen,
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);
void meta_display_set_input_focus_xwindow (MetaDisplay *display,
MetaScreen *screen,
MetaFocusType type,
Window window,
guint32 timestamp);
#endif

File diff suppressed because it is too large Load Diff

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)

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,8 +50,10 @@
#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>
@ -77,10 +79,6 @@
#include <girepository.h>
#endif
#include "x11/session.h"
#include "wayland/meta-wayland.h"
/*
* The exit code we'll return to our parent process when we eventually die.
*/
@ -192,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[] = {
{
@ -236,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}
};
@ -409,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);
@ -504,32 +497,6 @@ meta_register_with_session (void)
g_free (opt_client_id);
}
/**
* 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)
{
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
GError *error = NULL;
if (!meta_wayland_compositor_activate_session (compositor, &error))
{
g_warning ("Could not activate session: %s\n", error->message);
g_error_free (error);
return FALSE;
}
}
return TRUE;
}
/**
* meta_run: (skip)
*

View File

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

@ -39,7 +39,6 @@
#include <gbm.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xfixes.h>
@ -47,10 +46,9 @@
#include "meta-cursor-tracker-private.h"
#include "screen-private.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
@ -571,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))
@ -1079,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
@ -1101,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
@ -1148,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

@ -653,10 +653,8 @@ meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
{
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);
}
/**

View File

@ -650,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

@ -34,6 +34,7 @@
#include "util-private.h"
#include <meta/errors.h>
#include "monitor-private.h"
#include "meta-wayland-private.h"
#include "meta-dbus-xrandr.h"

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

@ -64,6 +64,8 @@ struct _MetaScreen
Visual *default_xvisual;
MetaRectangle rect; /* Size of screen; rect.x & rect.y are always 0 */
MetaUI *ui;
MetaTabPopup *tab_popup, *ws_popup;
MetaTilePreview *tile_preview;
guint tile_preview_timeout_id;
@ -82,6 +84,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;
@ -147,9 +151,25 @@ void meta_screen_foreach_window (MetaScreen *scree
void meta_screen_update_cursor (MetaScreen *screen);
void meta_screen_update_tile_preview (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_tile_preview_update (MetaScreen *screen,
gboolean delay);
void meta_screen_hide_tile_preview (MetaScreen *screen);
void meta_screen_tile_preview_hide (MetaScreen *screen);
MetaWindow* meta_screen_get_mouse_window (MetaScreen *screen,
MetaWindow *not_this_one);

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,
@ -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;
@ -761,6 +760,10 @@ meta_screen_new (MetaDisplay *display,
screen->ui = meta_ui_new (screen->display->xdisplay,
screen->xscreen);
screen->tab_popup = NULL;
screen->ws_popup = NULL;
screen->tile_preview = NULL;
screen->tile_preview_timeout_id = 0;
screen->stack = meta_stack_new (screen);
@ -808,8 +811,11 @@ meta_screen_free (MetaScreen *screen,
meta_display_grab (display);
meta_compositor_unmanage_screen (screen->display->compositor,
screen);
if (screen->display->compositor)
{
meta_compositor_unmanage_screen (screen->display->compositor,
screen);
}
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
@ -862,6 +868,9 @@ meta_screen_free (MetaScreen *screen,
if (screen->tile_preview_timeout_id)
g_source_remove (screen->tile_preview_timeout_id);
if (screen->tile_preview)
meta_tile_preview_free (screen->tile_preview);
g_free (screen->screen_name);
g_object_unref (screen);
@ -1423,8 +1432,255 @@ meta_screen_update_cursor (MetaScreen *screen)
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
meta_screen_update_tile_preview_timeout (gpointer data)
meta_screen_tile_preview_update_timeout (gpointer data)
{
MetaScreen *screen = data;
MetaWindow *window = screen->display->grab_window;
@ -1432,6 +1688,22 @@ meta_screen_update_tile_preview_timeout (gpointer data)
screen->tile_preview_timeout_id = 0;
if (!screen->tile_preview)
{
Window xwindow;
gulong create_serial;
MetaStackWindow stack_window;
screen->tile_preview = meta_tile_preview_new (screen->number);
xwindow = meta_tile_preview_get_xwindow (screen->tile_preview,
&create_serial);
stack_window.any.type = META_WINDOW_CLIENT_TYPE_X11;
stack_window.x11.xwindow = xwindow;
meta_stack_tracker_record_add (screen->stack_tracker,
&stack_window,
create_serial);
}
if (window)
{
switch (window->tile_mode)
@ -1456,16 +1728,12 @@ meta_screen_update_tile_preview_timeout (gpointer data)
if (needs_preview)
{
MetaRectangle tile_rect;
int monitor;
monitor = meta_window_get_current_tile_monitor_number (window);
meta_window_get_current_tile_area (window, &tile_rect);
meta_compositor_show_tile_preview (screen->display->compositor,
screen, window, &tile_rect, monitor);
meta_tile_preview_show (screen->tile_preview, &tile_rect);
}
else
meta_compositor_hide_tile_preview (screen->display->compositor,
screen);
meta_tile_preview_hide (screen->tile_preview);
return FALSE;
}
@ -1473,7 +1741,7 @@ meta_screen_update_tile_preview_timeout (gpointer data)
#define TILE_PREVIEW_TIMEOUT_MS 200
void
meta_screen_update_tile_preview (MetaScreen *screen,
meta_screen_tile_preview_update (MetaScreen *screen,
gboolean delay)
{
if (delay)
@ -1483,7 +1751,7 @@ meta_screen_update_tile_preview (MetaScreen *screen,
screen->tile_preview_timeout_id =
g_timeout_add (TILE_PREVIEW_TIMEOUT_MS,
meta_screen_update_tile_preview_timeout,
meta_screen_tile_preview_update_timeout,
screen);
}
else
@ -1491,18 +1759,18 @@ meta_screen_update_tile_preview (MetaScreen *screen,
if (screen->tile_preview_timeout_id > 0)
g_source_remove (screen->tile_preview_timeout_id);
meta_screen_update_tile_preview_timeout ((gpointer)screen);
meta_screen_tile_preview_update_timeout ((gpointer)screen);
}
}
void
meta_screen_hide_tile_preview (MetaScreen *screen)
meta_screen_tile_preview_hide (MetaScreen *screen)
{
if (screen->tile_preview_timeout_id > 0)
g_source_remove (screen->tile_preview_timeout_id);
meta_compositor_hide_tile_preview (screen->display->compositor,
screen);
if (screen->tile_preview)
meta_tile_preview_hide (screen->tile_preview);
}
MetaWindow*
@ -1510,19 +1778,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;
}
@ -1804,11 +2091,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;
@ -2519,9 +2823,10 @@ on_monitors_changed (MetaMonitorManager *manager,
&changes);
}
meta_compositor_sync_screen_size (screen->display->compositor,
screen,
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);

View File

@ -1041,7 +1041,7 @@ stack_tracker_event_received (MetaStackTracker *tracker,
if (op->any.serial < tracker->xserver_serial)
{
/* g_warning ("Spurious X event received affecting stack; doing full re-query"); */
g_warning ("Spurious X event received affecting stack; doing full re-query");
resync_verified_stack_with_xserver_stack (tracker);
meta_stack_tracker_dump (tracker);
return;
@ -1245,9 +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,
tracker->screen,
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)

View File

@ -38,15 +38,12 @@
#include "screen-private.h"
#include <meta/util.h>
#include "stack.h"
#include "iconcache.h"
#include <X11/Xutil.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
#include "x11/iconcache.h"
#include "x11/group-private.h"
#include "wayland/meta-wayland-types.h"
#include "meta-wayland-types.h"
typedef struct _MetaWindowQueue MetaWindowQueue;
@ -65,28 +62,13 @@ typedef enum {
#define NUMBER_OF_QUEUES 3
typedef enum {
_NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0,
_NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1,
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
} MetaBypassCompositorHintValue;
typedef enum
{
META_IS_CONFIGURE_REQUEST = 1 << 0,
META_DO_GRAVITY_ADJUST = 1 << 1,
META_IS_USER_ACTION = 1 << 2,
META_IS_MOVE_ACTION = 1 << 3,
META_IS_RESIZE_ACTION = 1 << 4,
META_IS_WAYLAND_RESIZE = 1 << 5
} MetaMoveResizeFlags;
typedef enum
{
META_MOVE_RESIZE_RESULT_MOVED = 1 << 0,
META_MOVE_RESIZE_RESULT_RESIZED = 1 << 1,
META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2,
} MetaMoveResizeResultFlags;
struct _MetaWindow
{
@ -103,16 +85,19 @@ struct _MetaWindow
MetaFrame *frame;
int depth;
Visual *xvisual;
Colormap colormap;
char *desc; /* used in debug spew */
char *title;
char *icon_name;
GdkPixbuf *icon;
GdkPixbuf *mini_icon;
MetaIconCache icon_cache;
Pixmap wm_hints_pixmap;
Pixmap wm_hints_mask;
MetaWindowType type;
Atom type_atom;
/* NOTE these five are not in UTF-8, we just treat them as random
* binary data
@ -174,8 +159,8 @@ struct _MetaWindow
/* Whether we're fullscreen */
guint fullscreen : 1;
/* Whether the window is marked as urgent */
guint urgent : 1;
/* Whether the urgent flag of WM_HINTS is set */
guint wm_hints_urgent : 1;
/* Whether we have to fullscreen after placement */
guint fullscreen_after_placement : 1;
@ -277,6 +262,13 @@ struct _MetaWindow
guint has_move_func : 1;
guint has_resize_func : 1;
guint has_fullscreen_func : 1;
/* Weird "_NET_WM_STATE_MODAL" flag */
guint wm_state_modal : 1;
/* TRUE if the client forced these on */
guint wm_state_skip_taskbar : 1;
guint wm_state_skip_pager : 1;
/* Computed whether to skip taskbar or not */
guint skip_taskbar : 1;
@ -330,6 +322,15 @@ struct _MetaWindow
/* Transient parent is a root window */
guint transient_parent_is_root_window : 1;
/* Info on which props we got our attributes from */
guint using_net_wm_name : 1; /* vs. plain wm_name */
guint using_net_wm_visible_name : 1; /* tracked so we can clear it */
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
/* icon props have changed */
guint need_reread_icon : 1;
/* if TRUE, window was maximized at start of current grab op */
guint shaken_loose : 1;
@ -430,6 +431,8 @@ struct _MetaWindow
* gives the position and size of the client window (i.e. ignoring
* the frame).
*
* Position valid if user_has_moved, size valid if user_has_resized
*
* Position always in root coords, unlike window->rect.
*/
MetaRectangle user_rect;
@ -468,24 +471,10 @@ struct _MetaWindowClass
{
GObjectClass parent_class;
void (*manage) (MetaWindow *window);
void (*unmanage) (MetaWindow *window);
void (*ping) (MetaWindow *window,
guint32 serial);
void (*delete) (MetaWindow *window,
guint32 timestamp);
void (*kill) (MetaWindow *window);
void (*focus) (MetaWindow *window,
guint32 timestamp);
void (*move_resize_internal) (MetaWindow *window,
int gravity,
MetaRectangle requested_rect,
MetaRectangle constrained_rect,
MetaMoveResizeFlags flags,
MetaMoveResizeResultFlags *result);
void (*get_default_skip_hints) (MetaWindow *window,
gboolean *skip_taskbar_out,
gboolean *skip_pager_out);
void (*workspace_changed) (MetaWindow *window, int old_workspace);
void (*focus) (MetaWindow *window);
void (*raised) (MetaWindow *window);
void (*unmanaged) (MetaWindow *window);
};
/* These differ from window->has_foo_func in that they consider
@ -578,6 +567,9 @@ void meta_window_change_workspace (MetaWindow *window,
/* Return whether the window should be currently mapped */
gboolean meta_window_should_be_showing (MetaWindow *window);
/* See warning in window.c about this function */
gboolean __window_is_terminal (MetaWindow *window);
void meta_window_update_struts (MetaWindow *window);
/* this gets root coords */
@ -611,6 +603,12 @@ void meta_window_get_geometry (MetaWindow *window,
void meta_window_update_unfocused_button_grabs (MetaWindow *window);
/* Sends a client message */
void meta_window_send_icccm_message (MetaWindow *window,
Atom atom,
guint32 timestamp);
void meta_window_move_resize_request(MetaWindow *window,
guint value_mask,
int gravity,
@ -636,6 +634,12 @@ void meta_window_show_menu (MetaWindow *window,
int button,
guint32 timestamp);
gboolean meta_window_titlebar_is_onscreen (MetaWindow *window);
void meta_window_shove_titlebar_onscreen (MetaWindow *window);
void meta_window_set_gravity (MetaWindow *window,
int gravity);
#ifdef HAVE_XSYNC
void meta_window_update_sync_request_counter (MetaWindow *window,
gint64 new_counter_value);
@ -648,7 +652,6 @@ void meta_window_handle_mouse_grab_op_xevent (MetaWindow *window,
GList* meta_window_get_workspaces (MetaWindow *window);
int meta_window_get_current_tile_monitor_number (MetaWindow *window);
void meta_window_get_current_tile_area (MetaWindow *window,
MetaRectangle *tile_area);
@ -680,8 +683,9 @@ void meta_window_update_layer (MetaWindow *window);
void meta_window_recalc_features (MetaWindow *window);
void meta_window_set_type (MetaWindow *window,
MetaWindowType type);
/* recalc_window_type is x11 only, wayland does its thing and then calls type_changed */
void meta_window_recalc_window_type (MetaWindow *window);
void meta_window_type_changed (MetaWindow *window);
void meta_window_frame_size_changed (MetaWindow *window);
@ -738,24 +742,9 @@ void meta_window_set_surface_mapped (MetaWindow *window,
Window meta_window_get_toplevel_xwindow (MetaWindow *window);
void meta_window_get_client_area_rect (const MetaWindow *window,
cairo_rectangle_int_t *rect);
void meta_window_activate_full (MetaWindow *window,
guint32 timestamp,
MetaClientType source_indication,
MetaWorkspace *workspace);
gboolean meta_window_is_client_decorated (MetaWindow *window);
void meta_window_update_monitor (MetaWindow *window);
void meta_window_set_urgent (MetaWindow *window,
gboolean urgent);
void meta_window_update_resize (MetaWindow *window,
gboolean snap,
int x, int y,
gboolean force);
#endif

View File

@ -35,12 +35,11 @@
*/
#define _GNU_SOURCE
#define _XOPEN_SOURCE 500 /* for gethostname() */
#define _SVID_SOURCE /* for gethostname() */
#include <config.h>
#include "window-props.h"
#include "window-x11.h"
#include "window-x11-private.h"
#include <meta/errors.h>
#include "xprops.h"
#include "frame.h"
@ -429,8 +428,9 @@ reload_net_wm_user_time_window (MetaWindow *window,
/**
* set_title_text:
*
* Called by set_window_title() to set the value of @target to @title.
* If required and @atom is set, it will update the appropriate property.
* Called by set_window_title() and set_icon_title() to set the value of
* @target to @title. It required and @atom is set, it will update the
* appropriate property.
*
* Returns: %TRUE if a new title was set.
*/
@ -488,18 +488,15 @@ static void
set_window_title (MetaWindow *window,
const char *title)
{
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = window_x11->priv;
char *new_title = NULL;
gboolean modified =
set_title_text (window,
priv->using_net_wm_visible_name,
window->using_net_wm_visible_name,
title,
window->display->atom__NET_WM_VISIBLE_NAME,
&new_title);
priv->using_net_wm_visible_name = modified;
window->using_net_wm_visible_name = modified;
meta_window_set_title (window, new_title);
@ -511,13 +508,10 @@ reload_net_wm_name (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = window_x11->priv;
if (value->type != META_PROP_VALUE_INVALID)
{
set_window_title (window, value->v.str);
priv->using_net_wm_name = TRUE;
window->using_net_wm_name = TRUE;
meta_verbose ("Using _NET_WM_NAME for new title of %s: \"%s\"\n",
window->desc, window->title);
@ -525,7 +519,7 @@ reload_net_wm_name (MetaWindow *window,
else
{
set_window_title (window, NULL);
priv->using_net_wm_name = FALSE;
window->using_net_wm_name = FALSE;
if (!initial)
meta_window_reload_property (window, XA_WM_NAME, FALSE);
}
@ -536,10 +530,7 @@ reload_wm_name (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = window_x11->priv;
if (priv->using_net_wm_name)
if (window->using_net_wm_name)
{
meta_verbose ("Ignoring WM_NAME \"%s\" as _NET_WM_NAME is set\n",
value->v.str);
@ -610,14 +601,71 @@ reload_mutter_hints (MetaWindow *window,
}
}
static void
set_icon_title (MetaWindow *window,
const char *title)
{
gboolean modified =
set_title_text (window,
window->using_net_wm_visible_icon_name,
title,
window->display->atom__NET_WM_VISIBLE_ICON_NAME,
&window->icon_name);
window->using_net_wm_visible_icon_name = modified;
}
static void
reload_net_wm_icon_name (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
if (value->type != META_PROP_VALUE_INVALID)
{
set_icon_title (window, value->v.str);
window->using_net_wm_icon_name = TRUE;
meta_verbose ("Using _NET_WM_ICON_NAME for new title of %s: \"%s\"\n",
window->desc, window->title);
}
else
{
set_icon_title (window, NULL);
window->using_net_wm_icon_name = FALSE;
if (!initial)
meta_window_reload_property (window, XA_WM_ICON_NAME, FALSE);
}
}
static void
reload_wm_icon_name (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
if (window->using_net_wm_icon_name)
{
meta_verbose ("Ignoring WM_ICON_NAME \"%s\" as _NET_WM_ICON_NAME is set\n",
value->v.str);
return;
}
if (value->type != META_PROP_VALUE_INVALID)
{
set_icon_title (window, value->v.str);
meta_verbose ("Using WM_ICON_NAME for new title of %s: \"%s\"\n",
window->desc, window->title);
}
else
{
set_icon_title (window, NULL);
}
}
static void
reload_net_wm_state (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
MetaWindowX11Private *priv = window_x11->priv;
int i;
/* We know this is only an initial window creation,
@ -635,9 +683,9 @@ reload_net_wm_state (MetaWindow *window,
window->maximized_horizontally = FALSE;
window->maximized_vertically = FALSE;
window->fullscreen = FALSE;
priv->wm_state_modal = FALSE;
priv->wm_state_skip_taskbar = FALSE;
priv->wm_state_skip_pager = FALSE;
window->wm_state_modal = FALSE;
window->wm_state_skip_taskbar = FALSE;
window->wm_state_skip_pager = FALSE;
window->wm_state_above = FALSE;
window->wm_state_below = FALSE;
window->wm_state_demands_attention = FALSE;
@ -657,11 +705,11 @@ reload_net_wm_state (MetaWindow *window,
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_HIDDEN)
window->minimize_after_placement = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MODAL)
priv->wm_state_modal = TRUE;
window->wm_state_modal = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_TASKBAR)
priv->wm_state_skip_taskbar = TRUE;
window->wm_state_skip_taskbar = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER)
priv->wm_state_skip_pager = TRUE;
window->wm_state_skip_pager = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN)
window->fullscreen_after_placement = TRUE;
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE)
@ -679,7 +727,7 @@ reload_net_wm_state (MetaWindow *window,
meta_verbose ("Reloaded _NET_WM_STATE for %s\n",
window->desc);
meta_window_x11_recalc_window_type (window);
meta_window_recalc_window_type (window);
meta_window_recalc_features (window);
}
@ -1390,9 +1438,10 @@ reload_wm_hints (MetaWindow *window,
gboolean initial)
{
Window old_group_leader;
gboolean urgent;
gboolean old_urgent;
old_group_leader = window->xgroup_leader;
old_urgent = window->wm_hints_urgent;
/* Fill in defaults */
window->input = TRUE;
@ -1400,7 +1449,7 @@ reload_wm_hints (MetaWindow *window,
window->xgroup_leader = None;
window->wm_hints_pixmap = None;
window->wm_hints_mask = None;
urgent = FALSE;
window->wm_hints_urgent = FALSE;
if (value->type != META_PROP_VALUE_INVALID)
{
@ -1422,7 +1471,7 @@ reload_wm_hints (MetaWindow *window,
window->wm_hints_mask = hints->icon_mask;
if (hints->flags & XUrgencyHint)
urgent = TRUE;
window->wm_hints_urgent = TRUE;
meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%lx pixmap: 0x%lx mask: 0x%lx\n",
window->input, window->initially_iconic,
@ -1439,7 +1488,20 @@ reload_wm_hints (MetaWindow *window,
meta_window_group_leader_changed (window);
}
meta_window_set_urgent (window, urgent);
/*
* Do not emit urgency notification on the inital property load
*/
if (!initial && (window->wm_hints_urgent != old_urgent))
g_object_notify (G_OBJECT (window), "urgent");
/*
* Do not emit signal for the initial property load, let the constructor to
* take care of it once the MetaWindow is fully constructed.
*
* Only emit if the property is both changed and set.
*/
if (!initial && window->wm_hints_urgent && !old_urgent)
g_signal_emit_by_name (window->display, "window-marked-urgent", window);
meta_icon_cache_property_changed (&window->icon_cache,
window->display,
@ -1671,6 +1733,8 @@ meta_display_init_window_prop_hooks (MetaDisplay *display)
{ XA_WM_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name, TRUE, TRUE },
{ display->atom__MUTTER_HINTS, META_PROP_VALUE_TEXT_PROPERTY, reload_mutter_hints, TRUE, TRUE },
{ display->atom__NET_WM_OPAQUE_REGION, META_PROP_VALUE_CARDINAL_LIST, reload_opaque_region, TRUE, TRUE },
{ display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8, reload_net_wm_icon_name, TRUE, FALSE },
{ XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE },
{ display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE },
{ display->atom__NET_STARTUP_ID, META_PROP_VALUE_UTF8, reload_net_startup_id, TRUE, FALSE },
{ display->atom__NET_WM_SYNC_REQUEST_COUNTER, META_PROP_VALUE_SYNC_COUNTER_LIST, reload_update_counter, TRUE, TRUE },

File diff suppressed because it is too large Load Diff

View File

@ -26,20 +26,6 @@
#include <meta/window.h>
#include <X11/Xlib.h>
G_BEGIN_DECLS
#define META_TYPE_WINDOW_X11 (meta_window_x11_get_type())
#define META_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_WINDOW_X11, MetaWindowX11))
#define META_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_WINDOW_X11, MetaWindowX11Class))
#define META_IS_WINDOW_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_WINDOW_X11))
#define META_IS_WINDOW_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_WINDOW_X11))
#define META_WINDOW_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_WINDOW_X11, MetaWindowX11Class))
GType meta_window_x11_get_type (void);
typedef struct _MetaWindowX11 MetaWindowX11;
typedef struct _MetaWindowX11Class MetaWindowX11Class;
void meta_window_x11_set_net_wm_state (MetaWindow *window);
void meta_window_x11_set_wm_state (MetaWindow *window);
@ -49,8 +35,6 @@ void meta_window_x11_update_opaque_region (MetaWindow *window);
void meta_window_x11_update_input_region (MetaWindow *window);
void meta_window_x11_update_shape_region (MetaWindow *window);
void meta_window_x11_recalc_window_type (MetaWindow *window);
gboolean meta_window_x11_configure_request (MetaWindow *window,
XEvent *event);
gboolean meta_window_x11_property_notify (MetaWindow *window,
@ -58,7 +42,4 @@ gboolean meta_window_x11_property_notify (MetaWindow *window,
gboolean meta_window_x11_client_message (MetaWindow *window,
XEvent *event);
void meta_window_x11_configure_notify (MetaWindow *window,
XConfigureEvent *event);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -91,6 +91,7 @@ item(hotplug_mode_update)
item(_NET_WM_SYNC_REQUEST)
item(_NET_WM_SYNC_REQUEST_COUNTER)
item(_NET_WM_VISIBLE_NAME)
item(_NET_WM_VISIBLE_ICON_NAME)
item(_NET_SUPPORTING_WM_CHECK)
/* But I suppose it's quite reasonable not to advertise using
@ -131,6 +132,7 @@ item(_NET_CLIENT_LIST)
item(_NET_CLIENT_LIST_STACKING)
item(_NET_WM_STATE_SKIP_TASKBAR)
item(_NET_WM_STATE_SKIP_PAGER)
item(_NET_WM_ICON_NAME)
item(_NET_WM_ICON)
item(_NET_WM_ICON_GEOMETRY)
item(_NET_WM_MOVERESIZE)

View File

@ -163,6 +163,13 @@ typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
* @META_GRAB_OP_KEYBOARD_RESIZING_NE: Resizing NE with keyboard
* @META_GRAB_OP_KEYBOARD_RESIZING_SW: Resizing SW with keyboard
* @META_GRAB_OP_KEYBOARD_RESIZING_NW: Resizing NS with keyboard
* @META_GRAB_OP_KEYBOARD_TABBING_NORMAL: Tabbing
* @META_GRAB_OP_KEYBOARD_TABBING_DOCK: Tabbing through docks
* @META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL: Escaping
* @META_GRAB_OP_KEYBOARD_ESCAPING_DOCK: Escaping through docks
* @META_GRAB_OP_KEYBOARD_ESCAPING_GROUP: Escaping through groups
* @META_GRAB_OP_KEYBOARD_TABBING_GROUP: Tabbing through groups
* @META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING: Switch to another workspace
* @META_GRAB_OP_CLICKING_MINIMIZE: Clicked minimize button
* @META_GRAB_OP_CLICKING_MAXIMIZE: Clicked maximize button
* @META_GRAB_OP_CLICKING_UNMAXIMIZE: Clicked unmaximize button
@ -207,6 +214,21 @@ typedef enum
META_GRAB_OP_KEYBOARD_RESIZING_SW,
META_GRAB_OP_KEYBOARD_RESIZING_NW,
/* Alt+Tab */
META_GRAB_OP_KEYBOARD_TABBING_NORMAL,
META_GRAB_OP_KEYBOARD_TABBING_DOCK,
/* Alt+Esc */
META_GRAB_OP_KEYBOARD_ESCAPING_NORMAL,
META_GRAB_OP_KEYBOARD_ESCAPING_DOCK,
META_GRAB_OP_KEYBOARD_ESCAPING_GROUP,
/* Alt+F6 */
META_GRAB_OP_KEYBOARD_TABBING_GROUP,
META_GRAB_OP_KEYBOARD_WORKSPACE_SWITCHING,
/* Frame button ops */
META_GRAB_OP_CLICKING_MINIMIZE,
META_GRAB_OP_CLICKING_MAXIMIZE,
@ -221,10 +243,7 @@ typedef enum
META_GRAB_OP_CLICKING_UNSTICK,
/* Special grab op when the compositor asked for a grab */
META_GRAB_OP_COMPOSITOR,
/* For when a client takes a popup grab */
META_GRAB_OP_WAYLAND_CLIENT,
META_GRAB_OP_COMPOSITOR
} MetaGrabOp;
/**

View File

@ -66,8 +66,6 @@ void meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_opacity_changed (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_surface_changed (MetaCompositor *compositor,
MetaWindow *window);
gboolean meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event,
@ -123,12 +121,4 @@ void meta_compositor_sync_screen_size (MetaCompositor *compositor,
void meta_compositor_flash_screen (MetaCompositor *compositor,
MetaScreen *screen);
void meta_compositor_show_tile_preview (MetaCompositor *compositor,
MetaScreen *screen,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
void meta_compositor_hide_tile_preview (MetaCompositor *compositor,
MetaScreen *screen);
#endif /* META_COMPOSITOR_H */

View File

@ -163,6 +163,10 @@ void meta_display_set_input_focus_window (MetaDisplay *display,
gboolean focus_frame,
guint32 timestamp);
void meta_display_request_take_focus (MetaDisplay *display,
MetaWindow *window,
guint32 timestamp);
/* meta_display_focus_the_no_focus_window is called when the
* designated no_focus_window should be focused, but is otherwise the
* same as meta_display_set_input_focus_window
@ -174,6 +178,8 @@ void meta_display_focus_the_no_focus_window (MetaDisplay *display,
GSList *meta_display_sort_windows_by_stacking (MetaDisplay *display,
GSList *windows);
Window meta_display_get_leader_window (MetaDisplay *display);
void meta_display_add_ignored_crossing_serial (MetaDisplay *display,
unsigned long serial);

View File

@ -28,7 +28,6 @@ GOptionContext *meta_get_option_context (void);
void meta_init (void);
int meta_run (void);
void meta_register_with_session (void);
gboolean meta_activate_session (void);
gboolean meta_get_replace_current_wm (void); /* Actually defined in util.c */
void meta_set_wm_name (const char *wm_name);

View File

@ -158,11 +158,6 @@ struct _MetaPluginClass
gint to,
MetaMotionDirection direction);
void (*show_tile_preview) (MetaPlugin *plugin,
MetaWindow *window,
MetaRectangle *tile_rect,
int tile_monitor_number);
void (*hide_tile_preview) (MetaPlugin *plugin);
/**
* MetaPluginClass::kill_window_effects:
@ -254,6 +249,9 @@ struct _MetaPluginInfo
GType meta_plugin_get_type (void);
gboolean meta_plugin_running (MetaPlugin *plugin);
gboolean meta_plugin_debug_mode (MetaPlugin *plugin);
const MetaPluginInfo * meta_plugin_get_info (MetaPlugin *plugin);
/**
@ -405,7 +403,8 @@ meta_plugin_end_modal (MetaPlugin *plugin,
MetaScreen *meta_plugin_get_screen (MetaPlugin *plugin);
void _meta_plugin_set_screen (MetaPlugin *plugin, MetaScreen *screen);
void
_meta_plugin_effect_started (MetaPlugin *plugin);
/* XXX: Putting this in here so it's in the public header. */
void meta_plugin_manager_set_plugin_type (GType gtype);

View File

@ -62,6 +62,7 @@
* @META_PREF_EDGE_TILING: edge tiling
* @META_PREF_FORCE_FULLSCREEN: force fullscreen
* @META_PREF_WORKSPACES_ONLY_ON_PRIMARY: workspaces only on primary
* @META_PREF_NO_TAB_POPUP: no tab popup
* @META_PREF_DRAGGABLE_BORDER_WIDTH: draggable border width
* @META_PREF_AUTO_MAXIMIZE: auto-maximize
*/
@ -99,6 +100,7 @@ typedef enum
META_PREF_EDGE_TILING,
META_PREF_FORCE_FULLSCREEN,
META_PREF_WORKSPACES_ONLY_ON_PRIMARY,
META_PREF_NO_TAB_POPUP,
META_PREF_DRAGGABLE_BORDER_WIDTH,
META_PREF_AUTO_MAXIMIZE
} MetaPreference;
@ -161,6 +163,9 @@ void meta_prefs_set_force_fullscreen (gboolean whether);
gboolean meta_prefs_get_workspaces_only_on_primary (void);
gboolean meta_prefs_get_no_tab_popup (void);
void meta_prefs_set_no_tab_popup (gboolean whether);
int meta_prefs_get_draggable_border_width (void);
gboolean meta_prefs_get_ignore_request_hide_titlebar (void);
@ -199,6 +204,8 @@ void meta_prefs_set_ignore_request_hide_titlebar (gboolean whether);
* @META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD: FILLME
* @META_KEYBINDING_ACTION_CYCLE_PANELS: FILLME
* @META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD: FILLME
* @META_KEYBINDING_ACTION_TAB_POPUP_SELECT: FILLME
* @META_KEYBINDING_ACTION_TAB_POPUP_CANCEL: FILLME
* @META_KEYBINDING_ACTION_SHOW_DESKTOP: FILLME
* @META_KEYBINDING_ACTION_PANEL_MAIN_MENU: FILLME
* @META_KEYBINDING_ACTION_PANEL_RUN_DIALOG: FILLME
@ -294,6 +301,8 @@ typedef enum _MetaKeyBindingAction
META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD,
META_KEYBINDING_ACTION_CYCLE_PANELS,
META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD,
META_KEYBINDING_ACTION_TAB_POPUP_SELECT,
META_KEYBINDING_ACTION_TAB_POPUP_CANCEL,
META_KEYBINDING_ACTION_SHOW_DESKTOP,
META_KEYBINDING_ACTION_PANEL_MAIN_MENU,
META_KEYBINDING_ACTION_PANEL_RUN_DIALOG,
@ -371,6 +380,20 @@ typedef enum
META_KEY_BINDING_IS_REVERSED = 1 << 3
} MetaKeyBindingFlags;
/**
* MetaKeyCombo:
* @keysym: keysym
* @keycode: keycode
* @modifiers: modifiers
*/
typedef struct _MetaKeyCombo MetaKeyCombo;
struct _MetaKeyCombo
{
unsigned int keysym;
unsigned int keycode;
MetaVirtualModifier modifiers;
};
/**
* MetaKeyHandlerFunc:
* @display: a #MetaDisplay
@ -388,14 +411,45 @@ typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
MetaKeyBinding *binding,
gpointer user_data);
typedef struct _MetaKeyHandler MetaKeyHandler;
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 *bindings;
/* 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;
GType meta_key_binding_get_type (void);
GList *meta_prefs_get_keybindings (void);
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
void meta_prefs_get_window_binding (const char *name,
unsigned int *keysym,
MetaVirtualModifier *modifiers);
void meta_prefs_get_overlay_binding (MetaKeyCombo *combo);
const char *meta_prefs_get_iso_next_group_option (void);
gboolean meta_prefs_get_visual_bell (void);
gboolean meta_prefs_bell_is_audible (void);
GDesktopVisualBellType meta_prefs_get_visual_bell_type (void);

View File

@ -72,13 +72,11 @@ typedef enum
* MetaMaximizeFlags:
* @META_MAXIMIZE_HORIZONTAL: Horizontal
* @META_MAXIMIZE_VERTICAL: Vertical
* @META_MAXIMIZE_BOTH: Both
*/
typedef enum
{
META_MAXIMIZE_HORIZONTAL = 1 << 0,
META_MAXIMIZE_VERTICAL = 1 << 1,
META_MAXIMIZE_BOTH = (1 << 0 | 1 << 1),
META_MAXIMIZE_VERTICAL = 1 << 1
} MetaMaximizeFlags;
/**
@ -125,6 +123,7 @@ MetaScreen *meta_window_get_screen (MetaWindow *window);
MetaDisplay *meta_window_get_display (MetaWindow *window);
Window meta_window_get_xwindow (MetaWindow *window);
MetaWindowType meta_window_get_window_type (MetaWindow *window);
Atom meta_window_get_window_type_atom (MetaWindow *window);
MetaWorkspace *meta_window_get_workspace (MetaWindow *window);
int meta_window_get_monitor (MetaWindow *window);
gboolean meta_window_is_on_all_workspaces (MetaWindow *window);
@ -164,6 +163,7 @@ void meta_window_change_workspace (MetaWindow *window,
MetaWorkspace *workspace);
GObject *meta_window_get_compositor_private (MetaWindow *window);
void meta_window_set_compositor_private (MetaWindow *window, GObject *priv);
void meta_window_configure_notify (MetaWindow *window, XConfigureEvent *event);
const char *meta_window_get_role (MetaWindow *window);
MetaStackLayer meta_window_get_layer (MetaWindow *window);
MetaWindow* meta_window_find_root_ancestor (MetaWindow *window);
@ -203,6 +203,7 @@ void meta_window_raise (MetaWindow *window);
void meta_window_lower (MetaWindow *window);
const char *meta_window_get_title (MetaWindow *window);
MetaWindow *meta_window_get_transient_for (MetaWindow *window);
Window meta_window_get_transient_for_as_xid (MetaWindow *window);
void meta_window_delete (MetaWindow *window,
guint32 timestamp);
guint meta_window_get_stable_sequence (MetaWindow *window);
@ -210,6 +211,7 @@ guint32 meta_window_get_user_time (MetaWindow *window);
int meta_window_get_pid (MetaWindow *window);
const char *meta_window_get_client_machine (MetaWindow *window);
gboolean meta_window_is_remote (MetaWindow *window);
gboolean meta_window_is_modal (MetaWindow *window);
gboolean meta_window_is_attached_dialog (MetaWindow *window);
const char *meta_window_get_mutter_hints (MetaWindow *window);
@ -250,16 +252,6 @@ void meta_window_begin_grab_op (MetaWindow *window,
gboolean frame_action,
guint32 timestamp);
gboolean meta_window_can_maximize (MetaWindow *window);
gboolean meta_window_can_minimize (MetaWindow *window);
gboolean meta_window_can_shade (MetaWindow *window);
gboolean meta_window_can_close (MetaWindow *window);
gboolean meta_window_is_always_on_all_workspaces (MetaWindow *window);
gboolean meta_window_is_above (MetaWindow *window);
gboolean meta_window_allows_move (MetaWindow *window);
gboolean meta_window_allows_resize (MetaWindow *window);
gboolean meta_window_titlebar_is_onscreen (MetaWindow *window);
void meta_window_shove_titlebar_onscreen (MetaWindow *window);
#endif

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Type=Application
_Name=Mutter (wayland compositor)
Exec=mutter-launch -- mutter --wayland --display-server
Exec=mutter-launch -- mutter --wayland
NoDisplay=true
# name of loadable control center module
X-GNOME-WMSettingsModule=metacity

109
src/run-mutter.sh Executable file
View File

@ -0,0 +1,109 @@
#! /bin/bash
if test -z "$XNEST_DISPLAY"; then
XNEST_DISPLAY=:8
fi
if test -z "$CLIENT_DISPLAY"; then
CLIENT_DISPLAY=:8
fi
if test -z "$MUTTER_DISPLAY"; then
export MUTTER_DISPLAY=$CLIENT_DISPLAY
fi
if test -z "$SCREENS"; then
SCREENS=1
fi
MAX_SCREEN=`echo $SCREENS-1 | bc`
if test "$DEBUG" = none; then
DEBUG=
elif test -z "$DEBUG"; then
DEBUG=
fi
if test -z "$CLIENTS"; then
CLIENTS=0
fi
if test -z "$SM_CLIENTS"; then
SM_CLIENTS=0
fi
if test -n "$EVIL_TEST"; then
TEST_CLIENT='./wm-tester/wm-tester --evil'
fi
if test -n "$ICON_TEST"; then
TEST_CLIENT='./wm-tester/wm-tester --icon-windows'
fi
if test -n "$DEMO_TEST"; then
TEST_CLIENT='./tools/mutter-window-demo'
fi
if test -n "$XINERAMA"; then
XINERAMA_FLAGS='+xinerama'
fi
export EF_ALLOW_MALLOC_0=1
if test -z "$ONLY_WM"; then
echo "Launching Xnest"
Xnest -ac $XNEST_DISPLAY -scrns $SCREENS -geometry 640x480 -bw 15 $XINERAMA_FLAGS &
## usleep 800000
sleep 1
if test -n "$XMON_DIR"; then
echo "Launching xmond"
$XMON_DIR/xmonui | $XMON_DIR/xmond -server localhost:$XNEST_DISPLAY &
sleep 1
fi
if test -n "$XSCOPE_DIR"; then
## xscope doesn't like to die when it should, it backgrounds itself
killall -9 xscope
killall -9 xscope
echo "Launching xscope"
DISPLAY= $XSCOPE_DIR/xscope -o1 -i28 > xscoped-replies.txt &
export MUTTER_DISPLAY=localhost:28
sleep 1
fi
echo "Launching clients"
if test -n "$TEST_CLIENT"; then
for I in `seq 0 $MAX_SCREEN`; do
DISPLAY=$CLIENT_DISPLAY.$I $TEST_CLIENT &
done
fi
if test $CLIENTS != 0; then
for I in `seq 1 $CLIENTS`; do
echo "Launching xterm $I"
DISPLAY=$CLIENT_DISPLAY xterm -geometry 25x15 &
done
fi
if test $SM_CLIENTS != 0; then
for I in `seq 1 $SM_CLIENTS`; do
echo "Launching gnome-terminal $I"
DISPLAY=$CLIENT_DISPLAY gnome-terminal --geometry 25x15 &
done
fi
if test -e ~/.Xmodmap; then
DISPLAY=$CLIENT_DISPLAY xmodmap ~/.Xmodmap
fi
usleep 50000
for I in `seq 0 $MAX_SCREEN`; do
DISPLAY=$CLIENT_DISPLAY.$I xsetroot -solid royalblue3
done
fi
if test -z "$ONLY_SETUP"; then
MUTTER_VERBOSE=1 MUTTER_USE_LOGFILE=1 MUTTER_DEBUG_BUTTON_GRABS=1 exec $DEBUG ./mutter $OPTIONS
fi

224
src/ui/draw-workspace.c Normal file
View File

@ -0,0 +1,224 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Draw a workspace */
/* This file should not be modified to depend on other files in
* libwnck or mutter, since it's used in both of them
*/
/*
* Copyright (C) 2002 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "draw-workspace.h"
#include "theme-private.h"
static void
get_window_rect (const WnckWindowDisplayInfo *win,
int screen_width,
int screen_height,
const GdkRectangle *workspace_rect,
GdkRectangle *rect)
{
double width_ratio, height_ratio;
int x, y, width, height;
width_ratio = (double) workspace_rect->width / (double) screen_width;
height_ratio = (double) workspace_rect->height / (double) screen_height;
x = win->x;
y = win->y;
width = win->width;
height = win->height;
x *= width_ratio;
y *= height_ratio;
width *= width_ratio;
height *= height_ratio;
x += workspace_rect->x;
y += workspace_rect->y;
if (width < 3)
width = 3;
if (height < 3)
height = 3;
rect->x = x;
rect->y = y;
rect->width = width;
rect->height = height;
}
static void
draw_window (GtkWidget *widget,
cairo_t *cr,
const WnckWindowDisplayInfo *win,
const GdkRectangle *winrect,
GtkStateFlags state)
{
GdkPixbuf *icon;
int icon_x, icon_y, icon_w, icon_h;
gboolean is_active;
GdkRGBA color;
GtkStyleContext *style;
is_active = win->is_active;
cairo_save (cr);
cairo_rectangle (cr, winrect->x, winrect->y, winrect->width, winrect->height);
cairo_clip (cr);
style = gtk_widget_get_style_context (widget);
if (is_active)
meta_gtk_style_get_light_color (style, state, &color);
else
gtk_style_context_get_background_color (style, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_rectangle (cr,
winrect->x + 1, winrect->y + 1,
MAX (0, winrect->width - 2), MAX (0, winrect->height - 2));
cairo_fill (cr);
icon = win->icon;
icon_w = icon_h = 0;
if (icon)
{
icon_w = gdk_pixbuf_get_width (icon);
icon_h = gdk_pixbuf_get_height (icon);
/* If the icon is too big, fall back to mini icon.
* We don't arbitrarily scale the icon, because it's
* just too slow on my Athlon 850.
*/
if (icon_w > (winrect->width - 2) ||
icon_h > (winrect->height - 2))
{
icon = win->mini_icon;
if (icon)
{
icon_w = gdk_pixbuf_get_width (icon);
icon_h = gdk_pixbuf_get_height (icon);
/* Give up. */
if (icon_w > (winrect->width - 2) ||
icon_h > (winrect->height - 2))
icon = NULL;
}
}
}
if (icon)
{
icon_x = winrect->x + (winrect->width - icon_w) / 2;
icon_y = winrect->y + (winrect->height - icon_h) / 2;
cairo_save (cr);
gdk_cairo_set_source_pixbuf (cr, icon, icon_x, icon_y);
cairo_rectangle (cr, icon_x, icon_y, icon_w, icon_h);
cairo_clip (cr);
cairo_paint (cr);
cairo_restore (cr);
}
gtk_style_context_get_color (style, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_set_line_width (cr, 1.0);
cairo_rectangle (cr,
winrect->x + 0.5, winrect->y + 0.5,
MAX (0, winrect->width - 1), MAX (0, winrect->height - 1));
cairo_stroke (cr);
cairo_restore (cr);
}
void
wnck_draw_workspace (GtkWidget *widget,
cairo_t *cr,
int x,
int y,
int width,
int height,
int screen_width,
int screen_height,
GdkPixbuf *workspace_background,
gboolean is_active,
const WnckWindowDisplayInfo *windows,
int n_windows)
{
int i;
GdkRectangle workspace_rect;
GtkStateFlags state;
GtkStyleContext *style;
workspace_rect.x = x;
workspace_rect.y = y;
workspace_rect.width = width;
workspace_rect.height = height;
if (is_active)
state = GTK_STATE_FLAG_SELECTED;
else if (workspace_background)
state = GTK_STATE_FLAG_PRELIGHT;
else
state = GTK_STATE_FLAG_NORMAL;
style = gtk_widget_get_style_context (widget);
cairo_save (cr);
if (workspace_background)
{
gdk_cairo_set_source_pixbuf (cr, workspace_background, x, y);
cairo_paint (cr);
}
else
{
GdkRGBA color;
meta_gtk_style_get_dark_color (style,state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_rectangle (cr, x, y, width, height);
cairo_fill (cr);
}
i = 0;
while (i < n_windows)
{
const WnckWindowDisplayInfo *win = &windows[i];
GdkRectangle winrect;
get_window_rect (win, screen_width,
screen_height, &workspace_rect, &winrect);
draw_window (widget,
cr,
win,
&winrect,
state);
++i;
}
cairo_restore (cr);
}

59
src/ui/draw-workspace.h Normal file
View File

@ -0,0 +1,59 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Draw a workspace */
/* This file should not be modified to depend on other files in
* libwnck or metacity, since it's used in both of them
*/
/*
* Copyright (C) 2002 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WNCK_DRAW_WORKSPACE_H
#define WNCK_DRAW_WORKSPACE_H
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
typedef struct
{
GdkPixbuf *icon;
GdkPixbuf *mini_icon;
int x;
int y;
int width;
int height;
guint is_active : 1;
} WnckWindowDisplayInfo;
void wnck_draw_workspace (GtkWidget *widget,
cairo_t *cr,
int x,
int y,
int width,
int height,
int screen_width,
int screen_height,
GdkPixbuf *workspace_background,
gboolean is_active,
const WnckWindowDisplayInfo *windows,
int n_windows);
#endif

View File

@ -44,6 +44,8 @@
static void meta_frames_destroy (GtkWidget *object);
static void meta_frames_finalize (GObject *object);
static void meta_frames_style_updated (GtkWidget *widget);
static void meta_frames_map (GtkWidget *widget);
static void meta_frames_unmap (GtkWidget *widget);
static void meta_frames_update_prelit_control (MetaFrames *frames,
MetaUIFrame *frame,
@ -132,6 +134,9 @@ meta_frames_class_init (MetaFramesClass *class)
widget_class->style_updated = meta_frames_style_updated;
widget_class->map = meta_frames_map;
widget_class->unmap = meta_frames_unmap;
widget_class->draw = meta_frames_draw;
widget_class->destroy_event = meta_frames_destroy_event;
widget_class->button_press_event = meta_frames_button_press_event;
@ -226,7 +231,6 @@ meta_frames_init (MetaFrames *frames)
frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
update_style_contexts (frames);
gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE);
@ -518,26 +522,13 @@ MetaFrames*
meta_frames_new (int screen_number)
{
GdkScreen *screen;
MetaFrames *frames;
screen = gdk_display_get_screen (gdk_display_get_default (),
screen_number);
frames = g_object_new (META_TYPE_FRAMES,
"screen", screen,
"type", GTK_WINDOW_POPUP,
NULL);
/* Put the window at an arbitrary offscreen location; the one place
* it can't be is at -100x-100, since the meta_window_new() will
* mistake it for a window created via meta_create_offscreen_window()
* and ignore it, and we need this window to get frame-synchronization
* messages so that GTK+'s style change handling works.
*/
gtk_window_move (GTK_WINDOW (frames), -200, -200);
gtk_window_resize (GTK_WINDOW (frames), 1, 1);
return frames;
return g_object_new (META_TYPE_FRAMES,
"screen", screen,
NULL);
}
/* In order to use a style with a window it has to be attached to that
@ -644,6 +635,22 @@ meta_frames_unmanage_window (MetaFrames *frames,
meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
}
static void
meta_frames_map (GtkWidget *widget)
{
/* We override the parent map function to a no-op because we don't
* want to actually show the GDK window. But GTK needs to think that
* the widget is mapped or it won't deliver the events we care about.
*/
gtk_widget_set_mapped (widget, TRUE);
}
static void
meta_frames_unmap (GtkWidget *widget)
{
gtk_widget_set_mapped (widget, FALSE);
}
static MetaUIFrame*
meta_frames_lookup_window (MetaFrames *frames,
Window xwindow)

963
src/ui/tabpopup.c Normal file
View File

@ -0,0 +1,963 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter popup window thing showing windows you can tab to */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2002 Red Hat, Inc.
* Copyright (C) 2005 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 <config.h>
#include <meta/util.h>
#include "core.h"
#include "tabpopup.h"
/* FIXME these two includes are 100% broken ...
*/
#include "workspace-private.h"
#include "frame.h"
#include "draw-workspace.h"
#include <gtk/gtk.h>
#include <math.h>
#define OUTSIDE_SELECT_RECT 2
#define INSIDE_SELECT_RECT 2
typedef struct _TabEntry TabEntry;
struct _TabEntry
{
MetaTabEntryKey key;
char *title;
GdkPixbuf *icon, *dimmed_icon;
GtkWidget *widget;
GdkRectangle rect;
GdkRectangle inner_rect;
guint blank : 1;
};
struct _MetaTabPopup
{
GtkWidget *window;
GtkWidget *label;
GList *current;
GList *entries;
TabEntry *current_selected_entry;
GtkWidget *outline_window;
gboolean outline;
};
static GtkWidget* selectable_image_new (GdkPixbuf *pixbuf);
static void select_image (GtkWidget *widget);
static void unselect_image (GtkWidget *widget);
static GtkWidget* selectable_workspace_new (MetaWorkspace *workspace);
static void select_workspace (GtkWidget *widget);
static void unselect_workspace (GtkWidget *widget);
static gboolean
outline_window_draw (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
MetaTabPopup *popup;
TabEntry *te;
popup = data;
if (!popup->outline || popup->current_selected_entry == NULL)
return FALSE;
te = popup->current_selected_entry;
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_rectangle (cr,
0.5, 0.5,
te->rect.width - 1,
te->rect.height - 1);
cairo_stroke (cr);
cairo_rectangle (cr,
te->inner_rect.x - 0.5, te->inner_rect.y - 0.5,
te->inner_rect.width + 1,
te->inner_rect.height + 1);
cairo_stroke (cr);
return FALSE;
}
static GdkPixbuf*
dimm_icon (GdkPixbuf *pixbuf)
{
int x, y, pixel_stride, row_stride;
guchar *row, *pixels;
int w, h;
GdkPixbuf *dimmed_pixbuf;
if (gdk_pixbuf_get_has_alpha (pixbuf))
{
dimmed_pixbuf = gdk_pixbuf_copy (pixbuf);
}
else
{
dimmed_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
}
w = gdk_pixbuf_get_width (dimmed_pixbuf);
h = gdk_pixbuf_get_height (dimmed_pixbuf);
pixel_stride = 4;
row = gdk_pixbuf_get_pixels (dimmed_pixbuf);
row_stride = gdk_pixbuf_get_rowstride (dimmed_pixbuf);
for (y = 0; y < h; y++)
{
pixels = row;
for (x = 0; x < w; x++)
{
pixels[3] /= 2;
pixels += pixel_stride;
}
row += row_stride;
}
return dimmed_pixbuf;
}
static TabEntry*
tab_entry_new (const MetaTabEntry *entry,
gint screen_width,
gboolean outline)
{
TabEntry *te;
te = g_new (TabEntry, 1);
te->key = entry->key;
te->title = NULL;
if (entry->title)
{
gchar *str;
gchar *tmp;
gchar *formatter = "%s";
str = meta_g_utf8_strndup (entry->title, 4096);
if (entry->hidden)
{
formatter = "[%s]";
}
tmp = g_markup_printf_escaped (formatter, str);
g_free (str);
str = tmp;
if (entry->demands_attention)
{
/* Escape the whole line of text then markup the text and
* copy it back into the original buffer.
*/
tmp = g_strdup_printf ("<b>%s</b>", str);
g_free (str);
str = tmp;
}
te->title=g_strdup(str);
g_free (str);
}
te->widget = NULL;
te->icon = entry->icon;
te->blank = entry->blank;
te->dimmed_icon = NULL;
if (te->icon)
{
g_object_ref (G_OBJECT (te->icon));
if (entry->hidden)
te->dimmed_icon = dimm_icon (entry->icon);
}
if (outline)
{
te->rect.x = entry->rect.x;
te->rect.y = entry->rect.y;
te->rect.width = entry->rect.width;
te->rect.height = entry->rect.height;
te->inner_rect.x = entry->inner_rect.x;
te->inner_rect.y = entry->inner_rect.y;
te->inner_rect.width = entry->inner_rect.width;
te->inner_rect.height = entry->inner_rect.height;
}
return te;
}
MetaTabPopup*
meta_ui_tab_popup_new (const MetaTabEntry *entries,
int screen_number,
int entry_count,
int width,
gboolean outline)
{
MetaTabPopup *popup;
int i, left, top;
int height;
GtkWidget *grid;
GtkWidget *vbox;
GtkWidget *align;
GList *tmp;
GtkWidget *frame;
int max_label_width; /* the actual max width of the labels we create */
AtkObject *obj;
GdkScreen *screen;
int screen_width;
popup = g_new (MetaTabPopup, 1);
popup->outline_window = gtk_window_new (GTK_WINDOW_POPUP);
screen = gdk_display_get_screen (gdk_display_get_default (),
screen_number);
gtk_window_set_screen (GTK_WINDOW (popup->outline_window),
screen);
gtk_widget_set_app_paintable (popup->outline_window, TRUE);
gtk_widget_realize (popup->outline_window);
g_signal_connect (G_OBJECT (popup->outline_window), "draw",
G_CALLBACK (outline_window_draw), popup);
popup->window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_screen (GTK_WINDOW (popup->window),
screen);
gtk_window_set_position (GTK_WINDOW (popup->window),
GTK_WIN_POS_CENTER_ALWAYS);
/* enable resizing, to get never-shrink behavior */
gtk_window_set_resizable (GTK_WINDOW (popup->window),
TRUE);
popup->current = NULL;
popup->entries = NULL;
popup->current_selected_entry = NULL;
popup->outline = outline;
screen_width = gdk_screen_get_width (screen);
for (i = 0; i < entry_count; ++i)
{
TabEntry* new_entry = tab_entry_new (&entries[i], screen_width, outline);
popup->entries = g_list_prepend (popup->entries, new_entry);
}
popup->entries = g_list_reverse (popup->entries);
g_assert (width > 0);
height = i / width;
if (i % width)
height += 1;
grid = gtk_grid_new ();
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_set_border_width (GTK_CONTAINER (grid), 1);
gtk_container_add (GTK_CONTAINER (popup->window),
frame);
gtk_container_add (GTK_CONTAINER (frame),
vbox);
align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (align),
grid);
popup->label = gtk_label_new ("");
/* Set the accessible role of the label to a status bar so it
* will emit name changed events that can be used by screen
* readers.
*/
obj = gtk_widget_get_accessible (popup->label);
atk_object_set_role (obj, ATK_ROLE_STATUSBAR);
gtk_misc_set_padding (GTK_MISC (popup->label), 3, 3);
gtk_box_pack_end (GTK_BOX (vbox), popup->label, FALSE, FALSE, 0);
max_label_width = 0;
top = 0;
tmp = popup->entries;
while (tmp && top < height)
{
left = 0;
while (tmp && left < width)
{
GtkWidget *image;
GtkRequisition req;
TabEntry *te;
te = tmp->data;
if (te->blank)
{
/* just stick a widget here to avoid special cases */
image = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
}
else if (outline)
{
if (te->dimmed_icon)
{
image = selectable_image_new (te->dimmed_icon);
}
else
{
image = selectable_image_new (te->icon);
}
gtk_misc_set_padding (GTK_MISC (image),
INSIDE_SELECT_RECT + OUTSIDE_SELECT_RECT + 1,
INSIDE_SELECT_RECT + OUTSIDE_SELECT_RECT + 1);
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5);
}
else
{
image = selectable_workspace_new ((MetaWorkspace *) te->key);
}
te->widget = image;
gtk_grid_attach (GTK_GRID (grid),
te->widget,
left, top, 1, 1);
/* Efficiency rules! */
gtk_label_set_markup (GTK_LABEL (popup->label),
te->title);
gtk_widget_get_preferred_size (popup->label, &req, NULL);
max_label_width = MAX (max_label_width, req.width);
tmp = tmp->next;
++left;
}
++top;
}
/* remove all the temporary text */
gtk_label_set_text (GTK_LABEL (popup->label), "");
/* Make it so that we ellipsize if the text is too long */
gtk_label_set_ellipsize (GTK_LABEL (popup->label), PANGO_ELLIPSIZE_END);
/* Limit the window size to no bigger than screen_width/4 */
if (max_label_width>(screen_width/4))
{
max_label_width = screen_width/4;
}
max_label_width += 20; /* add random padding */
gtk_window_set_default_size (GTK_WINDOW (popup->window),
max_label_width,
-1);
return popup;
}
static void
free_tab_entry (gpointer data, gpointer user_data)
{
TabEntry *te;
te = data;
g_free (te->title);
if (te->icon)
g_object_unref (G_OBJECT (te->icon));
if (te->dimmed_icon)
g_object_unref (G_OBJECT (te->dimmed_icon));
g_free (te);
}
void
meta_ui_tab_popup_free (MetaTabPopup *popup)
{
meta_verbose ("Destroying tab popup window\n");
if (!popup)
{
meta_warning ("NULL passed to meta_ui_tab_popup_free\n");
return;
}
gtk_widget_destroy (popup->outline_window);
gtk_widget_destroy (popup->window);
g_list_foreach (popup->entries, free_tab_entry, NULL);
g_list_free (popup->entries);
g_free (popup);
}
void
meta_ui_tab_popup_set_showing (MetaTabPopup *popup,
gboolean showing)
{
if (showing)
{
gtk_widget_show_all (popup->window);
}
else
{
if (gtk_widget_get_visible (popup->window))
{
meta_verbose ("Hiding tab popup window\n");
gtk_widget_hide (popup->window);
meta_core_increment_event_serial (
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
}
}
}
static void
display_entry (MetaTabPopup *popup,
TabEntry *te)
{
GdkRectangle rect;
GdkWindow *window;
if (popup->current_selected_entry)
{
if (popup->outline)
unselect_image (popup->current_selected_entry->widget);
else
unselect_workspace (popup->current_selected_entry->widget);
}
gtk_label_set_markup (GTK_LABEL (popup->label), te->title);
if (popup->outline)
select_image (te->widget);
else
select_workspace (te->widget);
if (popup->outline)
{
cairo_region_t *region;
cairo_region_t *inner_region;
GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
window = gtk_widget_get_window (popup->outline_window);
/* Do stuff behind gtk's back */
gdk_window_hide (window);
meta_core_increment_event_serial (
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
rect = te->rect;
rect.x = 0;
rect.y = 0;
gdk_window_move_resize (window,
te->rect.x, te->rect.y,
te->rect.width, te->rect.height);
gdk_window_set_background_rgba (window, &black);
region = cairo_region_create_rectangle (&rect);
inner_region = cairo_region_create_rectangle (&te->inner_rect);
cairo_region_subtract (region, inner_region);
cairo_region_destroy (inner_region);
gdk_window_shape_combine_region (window,
region,
0, 0);
cairo_region_destroy (region);
/* This should piss off gtk a bit, but we don't want to raise
* above the tab popup. So, instead of calling gtk_widget_show,
* we manually set the window as mapped and then manually map it
* with gdk functions.
*/
gtk_widget_set_mapped (popup->outline_window, TRUE);
gdk_window_show_unraised (window);
}
/* Must be before we handle an expose for the outline window */
popup->current_selected_entry = te;
}
void
meta_ui_tab_popup_forward (MetaTabPopup *popup)
{
if (popup->current != NULL)
popup->current = popup->current->next;
if (popup->current == NULL)
popup->current = popup->entries;
if (popup->current != NULL)
{
TabEntry *te;
te = popup->current->data;
display_entry (popup, te);
}
}
void
meta_ui_tab_popup_backward (MetaTabPopup *popup)
{
if (popup->current != NULL)
popup->current = popup->current->prev;
if (popup->current == NULL)
popup->current = g_list_last (popup->entries);
if (popup->current != NULL)
{
TabEntry *te;
te = popup->current->data;
display_entry (popup, te);
}
}
MetaTabEntryKey
meta_ui_tab_popup_get_selected (MetaTabPopup *popup)
{
if (popup->current)
{
TabEntry *te;
te = popup->current->data;
return te->key;
}
else
return (MetaTabEntryKey)None;
}
void
meta_ui_tab_popup_select (MetaTabPopup *popup,
MetaTabEntryKey key)
{
GList *tmp;
/* Note, "key" may not be in the list of entries; other code assumes
* it's OK to pass in a key that isn't.
*/
tmp = popup->entries;
while (tmp != NULL)
{
TabEntry *te;
te = tmp->data;
if (te->key == key)
{
popup->current = tmp;
display_entry (popup, te);
return;
}
tmp = tmp->next;
}
}
#define META_TYPE_SELECT_IMAGE (meta_select_image_get_type ())
#define META_SELECT_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SELECT_IMAGE, MetaSelectImage))
typedef struct _MetaSelectImage MetaSelectImage;
typedef struct _MetaSelectImageClass MetaSelectImageClass;
struct _MetaSelectImage
{
GtkImage parent_instance;
guint selected : 1;
};
struct _MetaSelectImageClass
{
GtkImageClass parent_class;
};
static GType meta_select_image_get_type (void) G_GNUC_CONST;
static GtkWidget*
selectable_image_new (GdkPixbuf *pixbuf)
{
GtkWidget *w;
w = g_object_new (meta_select_image_get_type (), NULL);
gtk_image_set_from_pixbuf (GTK_IMAGE (w), pixbuf);
return w;
}
static void
select_image (GtkWidget *widget)
{
META_SELECT_IMAGE (widget)->selected = TRUE;
gtk_widget_queue_draw (widget);
}
static void
unselect_image (GtkWidget *widget)
{
META_SELECT_IMAGE (widget)->selected = FALSE;
gtk_widget_queue_draw (widget);
}
static void meta_select_image_class_init (MetaSelectImageClass *klass);
static gboolean meta_select_image_draw (GtkWidget *widget,
cairo_t *cr);
static GtkImageClass *parent_class;
GType
meta_select_image_get_type (void)
{
static GType image_type = 0;
if (!image_type)
{
static const GTypeInfo image_info =
{
sizeof (MetaSelectImageClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) meta_select_image_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (MetaSelectImage),
16, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
image_type = g_type_register_static (GTK_TYPE_IMAGE, "MetaSelectImage", &image_info, 0);
}
return image_type;
}
static void
meta_select_image_class_init (MetaSelectImageClass *klass)
{
GtkWidgetClass *widget_class;
parent_class = g_type_class_peek (gtk_image_get_type ());
widget_class = GTK_WIDGET_CLASS (klass);
widget_class->draw = meta_select_image_draw;
}
static gboolean
meta_select_image_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
if (META_SELECT_IMAGE (widget)->selected)
{
GtkMisc *misc;
GtkRequisition requisition;
GtkStyleContext *context;
GdkRGBA color;
int x, y, w, h;
gint xpad, ypad;
gfloat xalign, yalign;
misc = GTK_MISC (widget);
gtk_widget_get_requisition (widget, &requisition);
gtk_misc_get_alignment (misc, &xalign, &yalign);
gtk_misc_get_padding (misc, &xpad, &ypad);
x = (allocation.width - (requisition.width - xpad * 2)) * xalign + 0.5;
y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 0.5;
x -= INSIDE_SELECT_RECT + 1;
y -= INSIDE_SELECT_RECT + 1;
w = requisition.width - OUTSIDE_SELECT_RECT * 2 - 1;
h = requisition.height - OUTSIDE_SELECT_RECT * 2 - 1;
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_state (context,
gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (context, "color", &color);
cairo_set_line_width (cr, 2.0);
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
cairo_rectangle (cr, x, y, w + 1, h + 1);
cairo_stroke (cr);
cairo_set_line_width (cr, 1.0);
}
return GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);
}
#define META_TYPE_SELECT_WORKSPACE (meta_select_workspace_get_type ())
#define META_SELECT_WORKSPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SELECT_WORKSPACE, MetaSelectWorkspace))
typedef struct _MetaSelectWorkspace MetaSelectWorkspace;
typedef struct _MetaSelectWorkspaceClass MetaSelectWorkspaceClass;
struct _MetaSelectWorkspace
{
GtkDrawingArea parent_instance;
MetaWorkspace *workspace;
guint selected : 1;
};
struct _MetaSelectWorkspaceClass
{
GtkDrawingAreaClass parent_class;
};
static GType meta_select_workspace_get_type (void) G_GNUC_CONST;
#define SELECT_OUTLINE_WIDTH 2
#define MINI_WORKSPACE_WIDTH 48
static GtkWidget*
selectable_workspace_new (MetaWorkspace *workspace)
{
GtkWidget *widget;
double screen_aspect;
widget = g_object_new (meta_select_workspace_get_type (), NULL);
screen_aspect = (double) workspace->screen->rect.height /
(double) workspace->screen->rect.width;
/* account for select rect */
gtk_widget_set_size_request (widget,
MINI_WORKSPACE_WIDTH + SELECT_OUTLINE_WIDTH * 2,
MINI_WORKSPACE_WIDTH * screen_aspect + SELECT_OUTLINE_WIDTH * 2);
META_SELECT_WORKSPACE (widget)->workspace = workspace;
return widget;
}
static void
select_workspace (GtkWidget *widget)
{
META_SELECT_WORKSPACE(widget)->selected = TRUE;
gtk_widget_queue_draw (widget);
}
static void
unselect_workspace (GtkWidget *widget)
{
META_SELECT_WORKSPACE (widget)->selected = FALSE;
gtk_widget_queue_draw (widget);
}
static void meta_select_workspace_class_init (MetaSelectWorkspaceClass *klass);
static gboolean meta_select_workspace_draw (GtkWidget *widget,
cairo_t *cr);
GType
meta_select_workspace_get_type (void)
{
static GType workspace_type = 0;
if (!workspace_type)
{
static const GTypeInfo workspace_info =
{
sizeof (MetaSelectWorkspaceClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) meta_select_workspace_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (MetaSelectWorkspace),
16, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
workspace_type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
"MetaSelectWorkspace",
&workspace_info,
0);
}
return workspace_type;
}
static void
meta_select_workspace_class_init (MetaSelectWorkspaceClass *klass)
{
GtkWidgetClass *widget_class;
widget_class = GTK_WIDGET_CLASS (klass);
widget_class->draw = meta_select_workspace_draw;
}
/**
* meta_convert_meta_to_wnck:
* @window: the #MetaWindow
* @screen: the #MetaScreen the window is on
*
* Converts a #MetaWindow to a #WnckWindowDisplayInfo window
* that is used to build a thumbnail of a workspace.
**/
static WnckWindowDisplayInfo
meta_convert_meta_to_wnck (MetaWindow *window, MetaScreen *screen)
{
WnckWindowDisplayInfo wnck_window;
wnck_window.icon = window->icon;
wnck_window.mini_icon = window->mini_icon;
wnck_window.is_active = window->has_focus;
if (window->frame)
{
wnck_window.x = window->frame->rect.x;
wnck_window.y = window->frame->rect.y;
wnck_window.width = window->frame->rect.width;
wnck_window.height = window->frame->rect.height;
}
else
{
wnck_window.x = window->rect.x;
wnck_window.y = window->rect.y;
wnck_window.width = window->rect.width;
wnck_window.height = window->rect.height;
}
return wnck_window;
}
static gboolean
meta_select_workspace_draw (GtkWidget *widget,
cairo_t *cr)
{
MetaWorkspace *workspace;
WnckWindowDisplayInfo *windows;
GtkAllocation allocation;
int i, n_windows;
GList *tmp, *list;
workspace = META_SELECT_WORKSPACE (widget)->workspace;
list = meta_stack_list_windows (workspace->screen->stack, workspace);
n_windows = g_list_length (list);
windows = g_new (WnckWindowDisplayInfo, n_windows);
tmp = list;
i = 0;
while (tmp != NULL)
{
MetaWindow *window;
gboolean ignoreable_sticky;
window = tmp->data;
ignoreable_sticky = window->on_all_workspaces &&
workspace != workspace->screen->active_workspace;
if (window->skip_pager ||
!meta_window_showing_on_its_workspace (window) ||
window->unmaps_pending ||
ignoreable_sticky)
{
--n_windows;
}
else
{
windows[i] = meta_convert_meta_to_wnck (window, workspace->screen);
i++;
}
tmp = tmp->next;
}
g_list_free (list);
gtk_widget_get_allocation (widget, &allocation);
wnck_draw_workspace (widget,
cr,
SELECT_OUTLINE_WIDTH,
SELECT_OUTLINE_WIDTH,
allocation.width - SELECT_OUTLINE_WIDTH * 2,
allocation.height - SELECT_OUTLINE_WIDTH * 2,
workspace->screen->rect.width,
workspace->screen->rect.height,
NULL,
(workspace->screen->active_workspace == workspace),
windows,
n_windows);
g_free (windows);
if (META_SELECT_WORKSPACE (widget)->selected)
{
GtkStyleContext *context;
GdkRGBA color;
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_state (context,
gtk_widget_get_state_flags (widget));
gtk_style_context_lookup_color (context, "color", &color);
cairo_set_line_width (cr, SELECT_OUTLINE_WIDTH);
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
cairo_rectangle (cr,
SELECT_OUTLINE_WIDTH / 2.0, SELECT_OUTLINE_WIDTH / 2.0,
allocation.width - SELECT_OUTLINE_WIDTH,
allocation.height - SELECT_OUTLINE_WIDTH);
cairo_stroke (cr);
}
return TRUE;
}

65
src/ui/tabpopup.h Normal file
View File

@ -0,0 +1,65 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter tab popup window */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2005 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/>.
*/
#ifndef META_TABPOPUP_H
#define META_TABPOPUP_H
/* Don't include gtk.h or gdk.h here */
#include <meta/common.h>
#include <meta/boxes.h>
#include <X11/Xlib.h>
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
typedef struct _MetaTabEntry MetaTabEntry;
typedef struct _MetaTabPopup MetaTabPopup;
typedef void *MetaTabEntryKey;
struct _MetaTabEntry
{
MetaTabEntryKey key;
const char *title;
GdkPixbuf *icon;
MetaRectangle rect;
MetaRectangle inner_rect;
guint blank : 1;
guint hidden : 1;
guint demands_attention : 1;
};
MetaTabPopup* meta_ui_tab_popup_new (const MetaTabEntry *entries,
int screen_number,
int entry_count,
int width,
gboolean outline);
void meta_ui_tab_popup_free (MetaTabPopup *popup);
void meta_ui_tab_popup_set_showing (MetaTabPopup *popup,
gboolean showing);
void meta_ui_tab_popup_forward (MetaTabPopup *popup);
void meta_ui_tab_popup_backward (MetaTabPopup *popup);
MetaTabEntryKey meta_ui_tab_popup_get_selected (MetaTabPopup *popup);
void meta_ui_tab_popup_select (MetaTabPopup *popup,
MetaTabEntryKey key);
#endif

196
src/ui/tile-preview.c Normal file
View File

@ -0,0 +1,196 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter tile-preview marks the area a window will *ehm* snap to */
/*
* Copyright (C) 2010 Florian Müllner
*
* 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 <gtk/gtk.h>
#include <cairo.h>
#include "tile-preview.h"
#include "core.h"
#define OUTLINE_WIDTH 5 /* frame width in non-composite case */
struct _MetaTilePreview {
GtkWidget *preview_window;
gulong create_serial;
GdkRGBA *preview_color;
MetaRectangle tile_rect;
};
static gboolean
meta_tile_preview_draw (GtkWidget *widget,
cairo_t *cr,
gpointer user_data)
{
MetaTilePreview *preview = user_data;
cairo_set_line_width (cr, 1.0);
/* Fill the preview area with a transparent color */
gdk_cairo_set_source_rgba (cr, preview->preview_color);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
/* Use the opaque color for the border */
cairo_set_source_rgb (cr,
preview->preview_color->red,
preview->preview_color->green,
preview->preview_color->blue);
cairo_rectangle (cr,
0.5, 0.5,
preview->tile_rect.width - 1,
preview->tile_rect.height - 1);
cairo_stroke (cr);
return FALSE;
}
MetaTilePreview *
meta_tile_preview_new (int screen_number)
{
MetaTilePreview *preview;
GdkScreen *screen;
GtkStyleContext *context;
GtkWidgetPath *path;
guchar selection_alpha = 0xFF;
screen = gdk_display_get_screen (gdk_display_get_default (), screen_number);
preview = g_new (MetaTilePreview, 1);
preview->preview_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_screen (GTK_WINDOW (preview->preview_window), screen);
gtk_widget_set_app_paintable (preview->preview_window, TRUE);
preview->preview_color = NULL;
preview->tile_rect.x = preview->tile_rect.y = 0;
preview->tile_rect.width = preview->tile_rect.height = 0;
gtk_widget_set_visual (preview->preview_window,
gdk_screen_get_rgba_visual (screen));
path = gtk_widget_path_new ();
gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW);
context = gtk_style_context_new ();
gtk_style_context_set_path (context, path);
gtk_style_context_add_class (context,
GTK_STYLE_CLASS_RUBBERBAND);
gtk_widget_path_free (path);
gtk_style_context_get (context, GTK_STATE_FLAG_SELECTED,
"background-color", &preview->preview_color,
NULL);
/* The background-color for the .rubberband class should probably
* contain the correct alpha value - unfortunately, at least for now
* it doesn't. Hopefully the following workaround can be removed
* when GtkIconView gets ported to GtkStyleContext.
*/
gtk_style_context_get_style (context,
"selection-box-alpha", &selection_alpha,
NULL);
preview->preview_color->alpha = (double)selection_alpha / 0xFF;
g_object_unref (context);
/* We make an assumption that XCreateWindow will be the first operation
* when calling gtk_widget_realize() (via gdk_window_new()), or that it
* is at least "close enough".
*/
preview->create_serial = XNextRequest (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
gtk_widget_realize (preview->preview_window);
g_signal_connect (preview->preview_window, "draw",
G_CALLBACK (meta_tile_preview_draw), preview);
return preview;
}
void
meta_tile_preview_free (MetaTilePreview *preview)
{
gtk_widget_destroy (preview->preview_window);
if (preview->preview_color)
gdk_rgba_free (preview->preview_color);
g_free (preview);
}
void
meta_tile_preview_show (MetaTilePreview *preview,
MetaRectangle *tile_rect)
{
GdkWindow *window;
GdkRectangle old_rect;
if (gtk_widget_get_visible (preview->preview_window)
&& preview->tile_rect.x == tile_rect->x
&& preview->tile_rect.y == tile_rect->y
&& preview->tile_rect.width == tile_rect->width
&& preview->tile_rect.height == tile_rect->height)
return; /* nothing to do */
gtk_widget_show (preview->preview_window);
window = gtk_widget_get_window (preview->preview_window);
meta_core_lower_beneath_grab_window (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
GDK_WINDOW_XID (window),
gtk_get_current_event_time ());
old_rect.x = old_rect.y = 0;
old_rect.width = preview->tile_rect.width;
old_rect.height = preview->tile_rect.height;
gdk_window_invalidate_rect (window, &old_rect, FALSE);
preview->tile_rect = *tile_rect;
gdk_window_move_resize (window,
preview->tile_rect.x, preview->tile_rect.y,
preview->tile_rect.width, preview->tile_rect.height);
}
void
meta_tile_preview_hide (MetaTilePreview *preview)
{
gtk_widget_hide (preview->preview_window);
}
Window
meta_tile_preview_get_xwindow (MetaTilePreview *preview,
gulong *create_serial)
{
GdkWindow *window = gtk_widget_get_window (preview->preview_window);
if (create_serial)
*create_serial = preview->create_serial;
return GDK_WINDOW_XID (window);
}

36
src/ui/tile-preview.h Normal file
View File

@ -0,0 +1,36 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Meta tile preview */
/*
* Copyright (C) 2010 Florian Müllner
*
* 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_TILE_PREVIEW_H
#define META_TILE_PREVIEW_H
#include <meta/boxes.h>
typedef struct _MetaTilePreview MetaTilePreview;
MetaTilePreview *meta_tile_preview_new (int screen_number);
void meta_tile_preview_free (MetaTilePreview *preview);
void meta_tile_preview_show (MetaTilePreview *preview,
MetaRectangle *rect);
void meta_tile_preview_hide (MetaTilePreview *preview);
Window meta_tile_preview_get_xwindow (MetaTilePreview *preview,
gulong *create_serial);
#endif /* META_TILE_PREVIEW_H */

View File

@ -295,12 +295,9 @@ meta_ui_new (Display *xdisplay,
g_assert (gdisplay == gdk_display_get_default ());
ui->frames = meta_frames_new (XScreenNumberOfScreen (screen));
/* GTK+ needs the frame-sync protocol to work in order to properly
* handle style changes. This means that the dummy widget we create
* to get the style for title bars actually needs to be mapped
* and fully tracked as a MetaWindow. Horrible, but mostly harmless -
* the window is a 1x1 overide redirect window positioned offscreen.
*/
/* This does not actually show any widget. MetaFrames has been hacked so
* that showing it doesn't actually do anything. But we need the flags
* set for GTK to deliver events properly. */
gtk_widget_show (GTK_WIDGET (ui->frames));
g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui);

View File

@ -178,4 +178,7 @@ int meta_ui_get_drag_threshold (MetaUI *ui);
MetaUIDirection meta_ui_get_direction (void);
#include "tabpopup.h"
#include "tile-preview.h"
#endif

View File

@ -48,7 +48,7 @@ data_offer_accept (struct wl_client *client,
* this be a wl_data_device request? */
if (offer->source)
wl_data_source_send_target (offer->source->resource, mime_type);
offer->source->accept (offer->source, serial, mime_type);
}
static void
@ -58,9 +58,9 @@ data_offer_receive (struct wl_client *client, struct wl_resource *resource,
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (offer->source)
wl_data_source_send_send (offer->source->resource, mime_type, fd);
close (fd);
offer->source->send (offer->source, mime_type, fd);
else
close (fd);
}
static void
@ -82,8 +82,7 @@ destroy_data_offer (struct wl_resource *resource)
if (offer->source)
wl_list_remove (&offer->source_destroy_listener.link);
g_slice_free (MetaWaylandDataOffer, offer);
free (offer);
}
static void
@ -100,9 +99,13 @@ static struct wl_resource *
meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
MetaWaylandDataOffer *offer;
char **p;
offer = malloc (sizeof *offer);
if (offer == NULL)
return NULL;
offer->source = source;
offer->source_destroy_listener.notify = destroy_offer_data_source;
@ -175,7 +178,8 @@ destroy_drag_focus (struct wl_listener *listener, void *data)
static void
drag_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface)
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
MetaWaylandSeat *seat = drag_grab->seat;
@ -256,7 +260,7 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
if (drag_grab->drag_data_source)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
drag_grab_focus (&drag_grab->generic, NULL);
drag_grab_focus (&drag_grab->generic, NULL, NULL);
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
g_slice_free (MetaWaylandDragGrab, drag_grab);
@ -314,12 +318,8 @@ data_device_start_drag (struct wl_client *client,
{
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
MetaWaylandDragGrab *drag_grab;
if ((seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource)))
return;
/* FIXME: Check that client has implicit grab on the origin
* surface that matches the given time. */
/* FIXME: Check that the data source type array isn't empty. */
@ -332,7 +332,6 @@ data_device_start_drag (struct wl_client *client,
drag_grab->generic.pointer = &seat->pointer;
drag_grab->drag_client = client;
drag_grab->seat = seat;
if (source_resource)
{
@ -376,7 +375,7 @@ destroy_selection_data_source (struct wl_listener *listener, void *data)
}
}
static void
void
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
MetaWaylandDataSource *source,
guint32 serial)
@ -390,7 +389,7 @@ meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
if (seat->selection_data_source)
{
wl_data_source_send_cancelled (seat->selection_data_source->resource);
seat->selection_data_source->cancel (seat->selection_data_source);
wl_list_remove (&seat->selection_data_source_listener.link);
seat->selection_data_source = NULL;
}
@ -450,21 +449,47 @@ static const struct wl_data_device_interface data_device_interface = {
static void
destroy_data_source (struct wl_resource *resource)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source = wl_container_of (resource, source, resource);
char **p;
wl_array_for_each (p, &source->mime_types) free (*p);
wl_array_release (&source->mime_types);
}
g_slice_free (MetaWaylandDataSource, source);
static void
client_source_accept (MetaWaylandDataSource *source,
guint32 time, const char *mime_type)
{
wl_data_source_send_target (source->resource, mime_type);
}
static void
client_source_send (MetaWaylandDataSource *source,
const char *mime_type, int32_t fd)
{
wl_data_source_send_send (source->resource, mime_type, fd);
close (fd);
}
static void
client_source_cancel (MetaWaylandDataSource *source)
{
wl_data_source_send_cancelled (source->resource);
}
static void
create_data_source (struct wl_client *client,
struct wl_resource *resource, guint32 id)
{
MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource);
MetaWaylandDataSource *source;
source = malloc (sizeof *source);
if (source == NULL)
{
wl_resource_post_no_memory (resource);
return;
}
source->resource = wl_resource_create (client, &wl_data_source_interface,
MIN (META_WL_DATA_SOURCE_VERSION,
@ -472,6 +497,10 @@ create_data_source (struct wl_client *client,
wl_resource_set_implementation (source->resource, &data_source_interface,
source, destroy_data_source);
source->accept = client_source_accept;
source->send = client_source_send;
source->cancel = client_source_cancel;
wl_array_init (&source->mime_types);
}

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