Compare commits
60 Commits
wip/compos
...
3.11.92-wa
Author | SHA1 | Date | |
---|---|---|---|
![]() |
56e8c3b625 | ||
![]() |
ce3d9fb89f | ||
![]() |
27c018ab98 | ||
![]() |
a1427c7130 | ||
![]() |
91ad92c968 | ||
![]() |
f0c7b518e6 | ||
![]() |
5fa5ace5e6 | ||
![]() |
044c06bff3 | ||
![]() |
a3ccc4fd1c | ||
![]() |
0a20f7458c | ||
![]() |
9c94f8ae47 | ||
![]() |
f940292cfe | ||
![]() |
48a36356dd | ||
![]() |
f05983be42 | ||
![]() |
dfcefd3315 | ||
![]() |
3fe755e684 | ||
![]() |
0eb86de807 | ||
![]() |
ff635bad3b | ||
![]() |
43a409dec4 | ||
![]() |
b087fce062 | ||
![]() |
420f322910 | ||
![]() |
4bf6e0ae8c | ||
![]() |
97872e70a5 | ||
![]() |
be57308663 | ||
![]() |
33f1bd96f5 | ||
![]() |
9ba49358e5 | ||
![]() |
8b2b65246a | ||
![]() |
4fdbb466e1 | ||
![]() |
da48b18188 | ||
![]() |
a5f1790828 | ||
![]() |
6efcf2526d | ||
![]() |
d6a27195d3 | ||
![]() |
8f151842fb | ||
![]() |
6f7023bc6b | ||
![]() |
63b158e4da | ||
![]() |
b3364cad3e | ||
![]() |
3502cfba34 | ||
![]() |
5cc6becb63 | ||
![]() |
ae8f21a3dc | ||
![]() |
0cdf3bd383 | ||
![]() |
3de58189c0 | ||
![]() |
5270c469a3 | ||
![]() |
7504f16e59 | ||
![]() |
cdb7947dd1 | ||
![]() |
cdfc6f5b53 | ||
![]() |
fcb2ab41b2 | ||
![]() |
f5bd7c5f50 | ||
![]() |
cb549154aa | ||
![]() |
ada9610e30 | ||
![]() |
f11bf44525 | ||
![]() |
1f15c85c00 | ||
![]() |
8b4c5459c0 | ||
![]() |
d07d5d1328 | ||
![]() |
535685742a | ||
![]() |
62e45b6d5e | ||
![]() |
3c6dd5bf6d | ||
![]() |
0f85986340 | ||
![]() |
93ac0329db | ||
![]() |
c539dfe0d7 | ||
![]() |
1502d2a79f |
21
.gitignore
vendored
21
.gitignore
vendored
@@ -48,6 +48,7 @@ po/*.pot
|
||||
50-metacity-key.xml
|
||||
libmutter-wayland.pc
|
||||
mutter-wayland
|
||||
mutter-launch
|
||||
org.gnome.mutter.gschema.valid
|
||||
org.gnome.mutter.gschema.xml
|
||||
org.gnome.mutter.wayland.gschema.valid
|
||||
@@ -76,14 +77,13 @@ src/mutter-marshal.[ch]
|
||||
src/stamp-mutter-marshal.h
|
||||
src/meta-dbus-xrandr.[ch]
|
||||
src/meta-dbus-idle-monitor.[ch]
|
||||
src/meta-dbus-login1.[ch]
|
||||
src/mutter-plugins.pc
|
||||
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
|
||||
src/gtk-shell-protocol.c
|
||||
src/gtk-shell-server-protocol.h
|
||||
src/xdg-shell-protocol.c
|
||||
src/xdg-shell-server-protocol.h
|
||||
src/xserver-protocol.c
|
||||
src/xserver-server-protocol.h
|
||||
doc/reference/*.args
|
||||
doc/reference/*.bak
|
||||
doc/reference/*.hierarchy
|
||||
@@ -101,3 +101,10 @@ 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
|
||||
|
159
COMPLIANCE
159
COMPLIANCE
@@ -1,159 +0,0 @@
|
||||
Metacity Standards Compliance
|
||||
=============================
|
||||
$Id$
|
||||
|
||||
1) Introduction
|
||||
2) EWMH Compliance
|
||||
a. Root Window Properties
|
||||
b. Root Window Messages
|
||||
c. Application Window Properties
|
||||
d. Window Manager Protocols
|
||||
3) ICCCM Compliance
|
||||
|
||||
1) Introduction
|
||||
---------------
|
||||
|
||||
This document details metacity compliance with the relevent standards.
|
||||
The format of this document is as follows:
|
||||
|
||||
[-/+?] Hint Name/Feature Name (Version number)
|
||||
Errata/Comments
|
||||
|
||||
The first character indicates the level of compliance as follows:
|
||||
- none
|
||||
/ partial
|
||||
+ complete
|
||||
? unknown
|
||||
|
||||
The title indicates a feature or a hint in the specification, and the
|
||||
version number indicates the minimum version of the specification
|
||||
supported by metacity. Later versions may be supported if no
|
||||
incompatible changes have been made in the specification.
|
||||
|
||||
2) EWMH Compliance
|
||||
------------------
|
||||
|
||||
The EWMH, or Extended Window Manager Hints is a freedesktop.org-
|
||||
developed standard to support a number of conventions for
|
||||
communication between the window manager and clients. It builds on
|
||||
and extends the ICCCM (See Section 3). A copy of the current EWMH
|
||||
standard is available at http://freedesktop.org/Standards/wm-spec/
|
||||
|
||||
a. Root Window Properties
|
||||
-------------------------
|
||||
|
||||
+ _NET_SUPPORTED (1.3)
|
||||
|
||||
+ _NET_CLIENT_LIST (1.3)
|
||||
|
||||
+ _NET_NUMBER_OF_DESKTOPS (1.3)
|
||||
|
||||
+ _NET_DESKTOP_GEOMETRY (1.3)
|
||||
Metacity does not implement large desktops, so this is kept set to
|
||||
the screen size.
|
||||
|
||||
+ _NET_DESKTOP_VIEWPORT (1.3)
|
||||
Metacity does not implement viewports, so this is a constant (0,0).
|
||||
|
||||
+ _NET_CURRENT_DESKTOP (1.3)
|
||||
|
||||
+ _NET_DESKTOP_NAMES (1.3)
|
||||
|
||||
+ _NET_ACTIVE_WINDOW (1.3)
|
||||
|
||||
+ _NET_WORKAREA (1.3)
|
||||
|
||||
+ _NET_SUPPORTING_WM_CHECK (1.3)
|
||||
|
||||
+ _NET_VIRTUAL_ROOTS (1.3)
|
||||
Metacity does not read or set this property, but it does not use
|
||||
virtual roots to implement virtual desktops, so it complies with the
|
||||
specification.
|
||||
|
||||
+ _NET_DESKTOP_LAYOUT (1.3)
|
||||
|
||||
+ _NET_SHOWING_DESKTOP (1.3)
|
||||
|
||||
b. Root Window Messages
|
||||
-----------------------
|
||||
|
||||
+ _NET_CLOSE_WINDOW (1.3)
|
||||
|
||||
- _NET_MOVERESIZE_WINDOW (1.3)
|
||||
Metacity supports this message, but the specification is unclear on
|
||||
the layout of the detail value, and as such it is #if 0'd in the code
|
||||
|
||||
+ _NET_WM_MOVERESIZE (1.3)
|
||||
|
||||
- _NET_RESTACK_WINDOW (1.3)
|
||||
Metacity will raise or lower windows in response to this message,
|
||||
but the sibling restack modes are not supported, and it is currently
|
||||
#if 0'd in the code.
|
||||
|
||||
+ _NET_REQUEST_FRAME_EXTENTS (1.3)
|
||||
|
||||
c. Application Window Properties
|
||||
--------------------------------
|
||||
|
||||
+ _NET_WM_NAME (1.3)
|
||||
|
||||
+ _NET_WM_VISIBLE_NAME (1.3)
|
||||
Metacity does not set this property, but metacity will never display
|
||||
a name different from _NET_WM_NAME
|
||||
|
||||
+ _NET_WM_ICON_NAME (1.3)
|
||||
|
||||
+ _NET_WM_VISIBLE_ICON_NAME (1.3)
|
||||
Metacity does not set this property, but metacity will never display
|
||||
a name different from _NET_WM_NAME
|
||||
|
||||
+ _NET_WM_DESKTOP (1.3)
|
||||
|
||||
+ _NET_WM_WINDOW_TYPE (1.3)
|
||||
|
||||
/ _NET_WM_STATE (1.3)
|
||||
This property is read and updated according to the specification,
|
||||
but see caveat below.
|
||||
Metacity does not recognize separate vertical and horizontal
|
||||
maximization states. Currently metacity will do a two-dimensional
|
||||
maximization if either property is set.
|
||||
See: http://bugzilla.gnome.org/show_bug.cgi?id=113601
|
||||
Metacity doesn't implement viewports so _NET_WM_STATE_STICKY is
|
||||
unimplemented.
|
||||
|
||||
+ _NET_WM_ALLOWED_ACTIONS (1.3)
|
||||
Metacity keeps this hint up to date. The code is somewhat crufty
|
||||
and should be rewritten, though it is functional.
|
||||
See: http://bugzilla.gnome.org/show_bug.cgi?id=90420
|
||||
|
||||
+ _NET_WM_STRUT (1.3)
|
||||
|
||||
+ _NET_WM_STRUT_PARTIAL (1.3)
|
||||
|
||||
+ _NET_WM_ICON_GEOMETRY (1.3)
|
||||
Metacity uses this property to draw minimize/restore animations
|
||||
|
||||
+ _NET_WM_ICON (1.3)
|
||||
|
||||
+ _NET_WM_PID (1.3)
|
||||
|
||||
+ _NET_WM_HANDLED_ICONS (1.3)
|
||||
Metacity does not read or set this property. However, metacity
|
||||
never manages iconified windows, and so has no need to do so.
|
||||
|
||||
+ _NET_WM_USER_TIME (1.3)
|
||||
Metacity uses this property to prevent applications from stealing
|
||||
focus if supported by the toolkit.
|
||||
|
||||
+ _NET_FRAME_EXTENTS (1.3)
|
||||
If set in response to a _NET_REQUEST_FRAME_EXTENTS message received
|
||||
prior to the window being mapped, this may be an estimate. This is,
|
||||
however, expressly allowed by the specification.
|
||||
|
||||
d. Window Manager Protocols
|
||||
---------------------------
|
||||
+ _NET_WM_PING (1.3)
|
||||
|
||||
3) ICCCM Compliance
|
||||
-------------------
|
||||
TODO
|
298
HACKING
298
HACKING
@@ -1,298 +0,0 @@
|
||||
Intro...
|
||||
|
||||
Window managers have a few ways in which they are significantly different
|
||||
from other applications. This file, combined with the code overview in
|
||||
doc/code-overview.txt, should hopefully provide a series of relatively
|
||||
quick pointers (hopefully only a few minutes each) to some of the places
|
||||
one can look to orient themselves and get started. Some of this will be
|
||||
general to window managers on X, much will be specific to Metacity, and
|
||||
there's probably some information that's common to programs in general but
|
||||
is nonetheless useful.
|
||||
|
||||
Overview
|
||||
Administrative issues
|
||||
Minimal Building/Testing Environment
|
||||
Relevant standards and X properties
|
||||
Debugging and testing
|
||||
Debugging logs
|
||||
Adding information to the log
|
||||
Valgrind
|
||||
Testing Utilities
|
||||
Technical gotchas to keep in mind
|
||||
Other important reading
|
||||
Extra reading
|
||||
Ideas for tasks to work on
|
||||
|
||||
|
||||
Administrative issues
|
||||
Don't commit substantive code in here without asking hp@redhat.com.
|
||||
Adding translations, no-brainer typo fixes, etc. is fine.
|
||||
|
||||
The code could use cleanup in a lot of places, feel free to do so.
|
||||
|
||||
See http://developer.gnome.org/dotplan/for_maintainers.html for
|
||||
information on how to make a release. The only difference from those
|
||||
instructions is that the minor version number of a Metacity release
|
||||
should always be a number from the Fibonacci sequence.
|
||||
|
||||
Minimal Building/Testing Environment
|
||||
You do not need to _install_ a development version of Metacity to
|
||||
build, run and test it; you can run it from some temporary
|
||||
directory. Also, you do not need to build all of Gnome in order to
|
||||
build a development version of Metacity -- odds are, you may be able
|
||||
to build metacity from CVS without building any other modules.
|
||||
|
||||
As long as you have gtk+ >= 3.0 and GIO >= 2.25.10 with your distro
|
||||
(gtk+ >= 2.6 if you manually revert the change from bug 348633), you
|
||||
should be able to install your distro's development packages
|
||||
(e.g. gtk2-devel, glib-devel, startup-notification-devel on
|
||||
Fedora; also, remember to install the gnome-common package which is
|
||||
needed for building cvs versions of Gnome modules like Metacity) as
|
||||
well as the standard development tools (gcc, autoconf, automake,
|
||||
pkg-config, intltool, and libtool) and be ready to build and test
|
||||
Metacity. Steps to do so:
|
||||
|
||||
$ svn checkout http://svn.gnome.org/svn/metacity/trunk metacity
|
||||
$ cd metacity
|
||||
$ ./autogen.sh --prefix /usr
|
||||
$ make
|
||||
$ ./src/metacity --replace
|
||||
|
||||
Again, note that you do not need to run 'make install'.
|
||||
|
||||
Relevant standards and X properties
|
||||
There are two documents that describe some basics about how window
|
||||
managers should behave: the ICCCM (Inter-Client Communication Conventions
|
||||
Manual) and EWMH (Extended Window Manager Hints). You can find these at
|
||||
the following locations:
|
||||
ICCCM - http://tronche.com/gui/x/icccm/
|
||||
EWMH - :pserver:anoncvs@pdx.freedesktop.org:/cvs
|
||||
The ICCCM is usually available in RPM or DEB format as well. There is
|
||||
actually an online version of the EWMH, but it is almost always woefully
|
||||
out of date. Just get it from cvs with these commands (the backslash
|
||||
means include the stuff from the next line):
|
||||
cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions login
|
||||
cvs -d :pserver:anoncvs@cvs.freedesktop.org:/cvs/icccm-extensions \
|
||||
checkout wm-spec
|
||||
|
||||
DO NOT GO AND READ THOSE THINGS. THEY ARE REALLY, REALLY BORING.
|
||||
|
||||
If you do, you'll probably end up catching up on your sleep instead of
|
||||
hacking on Metacity. ;-) Instead, just look at the table of contents and
|
||||
glance at a page or two to get an idea of what's in there. Then only
|
||||
refer to it if you see something weird in the code and you don't know
|
||||
what it is but has some funny looking name like you see in one of those
|
||||
two documents.
|
||||
|
||||
You can refer to the COMPLIANCE file for additional information on these
|
||||
specifications and Metacity's compliance therewith.
|
||||
|
||||
One of the major things those documents cover that are useful to learn
|
||||
about immediately are X properties. The right way to learn about those,
|
||||
though, is through hand on experimentation with the xprop command (and
|
||||
then look up things you find from xprop in those two manuals if you're
|
||||
curious enough). First, try running
|
||||
xprop
|
||||
in a terminal and click on one of the windows on your screen. That gives
|
||||
you the x properties for that window. Look through them and get a basic
|
||||
idea of what's there for kicks. Note that you can get rid of some of the
|
||||
verboseness by grepping out the _NET_WM_ICON stuff, i.e.
|
||||
xprop | grep -v _NET_WM_ICON
|
||||
Next, try running
|
||||
xprop -root
|
||||
in a terminal. There's all the properties of the root window (which you
|
||||
can think of as the "main" Xserver window). You can also manually
|
||||
specify individual windows that you want the properties of with
|
||||
xprop -id <id>
|
||||
if you know the id of the window in question. You can get the id of a
|
||||
given window by either running xwininfo, e.g.
|
||||
xwininfo | grep "Window id" | cut -f 4 -d ' '
|
||||
or by looking at the _NET_CLIENT_STACKING property of the root
|
||||
window. Finally, it can also be useful to add "-spy" (without the
|
||||
quotes) to the xprop command to get it to continually monitor that
|
||||
window and report any changes to you.
|
||||
|
||||
Debugging information
|
||||
Trying to run a window manager under a typical debugger, such as gdb,
|
||||
unfortunately just doesn't work very well. So, we have to resort to
|
||||
other methods.
|
||||
|
||||
Debugging logs
|
||||
|
||||
First, note that you can start a new version of metacity to replace the
|
||||
existing one by running
|
||||
metacity --replace
|
||||
(which also comes in handy in the form "./src/metacity --replace" when
|
||||
trying to quickly test a small change while hacking on metacity without
|
||||
doing a full "make install", though I'm going off topic...) This will
|
||||
allow you to see any warnings printed at the terminal. Sometimes it's
|
||||
useful to have these directed to a logfile instead, which you can do by
|
||||
running
|
||||
METACITY_USE_LOGFILE=1 metacity --replace
|
||||
The logfile it uses will be printed in the terminal. Sometimes, it's
|
||||
useful to get more information than just warnings. You can set
|
||||
METACITY_VERBOSE to do that, like so:
|
||||
METACITY_VERBOSE=1 METACITY_USE_LOGFILE=1 metacity --replace
|
||||
(note that METACITY_VERBOSE=1 can be problematic without
|
||||
METACITY_USE_LOGFILE=1; avoid it unless running in from something that
|
||||
won't be managed by the new Metacity--see bug 305091 for more details).
|
||||
There are also other flags, such as METACITY_DEBUG, most of which I
|
||||
haven't tried and don't know what they do. Go to the source code
|
||||
directory and run
|
||||
grep "METACITY_" * | grep getenv
|
||||
to find out what the other ones are.
|
||||
|
||||
Adding information to the log
|
||||
|
||||
Since we can't single step with a debugger, we often have to fall back to
|
||||
the primitive method of getting information we want to know: adding
|
||||
"print" statements. Metacity has a fairly structured way to do this,
|
||||
using the functions meta_warning, meta_topic, and meta_verbose. All
|
||||
three have the same basic format as printf, except that meta_topic also
|
||||
takes a leading enumeration parameter to specify the type of message
|
||||
being shown (makes it easier for grepping in a verbose log). You'll find
|
||||
tons of examples in the source code if you need them; just do a quick
|
||||
grep or look in most any file. Note that meta_topic and meta_verbose
|
||||
messages only appear if verbosity is turned on. I tend to frequently add
|
||||
temporary meta_warning statements (or switch meta_topic or meta_verbose
|
||||
ones to meta_warning ones) and then undo the changes once I've learned
|
||||
the info that I needed.
|
||||
|
||||
There is also a meta_print_backtrace (which again is only active if
|
||||
verbosity is turned on) that can also be useful if you want to learn how
|
||||
a particular line of code gets called. And, of course, there's always
|
||||
g_assert if you want to make sure some section isn't executed (or isn't
|
||||
executed under certain conditions).
|
||||
|
||||
Valgrind
|
||||
|
||||
Valgrind is awesome for finding memory leaks or corruption and
|
||||
uninitialized variables. But I also tend to use it in a non-traditional
|
||||
way as a partial substitute for a normal debugger: it can provide me with
|
||||
a stack trace of where metacity is crashing if I made a change that
|
||||
caused it to do so, which is one of the major uses of debuggers. (And,
|
||||
what makes it cooler than a debugger is that there will also often be
|
||||
warnings pinpointing the cause of the crash from either some kind of
|
||||
simple memory corruption or an uninitialized variable). Sometimes, when
|
||||
I merely want to know what is calling a particular function I'll just
|
||||
throw in an "int i; printf("%d\n", i);" just because valgrind will give
|
||||
me a full stacktrace whenever it sees that uninitialized variable being
|
||||
used (yes, I could use meta_print_backtrace, but that means I have to
|
||||
turn verbosity on).
|
||||
|
||||
To run metacity under valgrind, use options typical for any Gnome
|
||||
program, such as
|
||||
valgrind --log-file=metacity.log --tool=memcheck --num-callers=48 \
|
||||
--leak-check=yes --leak-resolution=high --show-reachable=yes \
|
||||
./src/metacity --replace
|
||||
where, again, the backslashes mean to join all the stuff on the following
|
||||
line with the previous one.
|
||||
|
||||
However, there is a downside. Things run a little bit slowly, and it
|
||||
appears that you'll need about 1.5GB of ram, which unfortunately prevents
|
||||
most people from trying this.
|
||||
|
||||
Testing Utilities
|
||||
|
||||
src/run-metacity.sh
|
||||
The script src/run-metacity.sh is useful to hack on the window manager.
|
||||
It runs metacity in an Xnest. e.g.:
|
||||
CLIENTS=3 ./run-metacity.sh
|
||||
or
|
||||
DEBUG=memprof ./run-metacity.sh
|
||||
or
|
||||
DEBUG_TEST=1 ./run-metacity-sh
|
||||
or whatever.
|
||||
|
||||
metacity-message
|
||||
The tool metacity-message can be used as follows:
|
||||
metacity-message reload-theme
|
||||
metacity-message restart
|
||||
metacity-message enable-keybindings
|
||||
metacity-message disable-keybindings
|
||||
The first of these is useful for testing themes, the second is just
|
||||
another way (besides the --restart flag to metacity itself) of
|
||||
restarting metacity, and the third is useful for testing Metacity when
|
||||
running it under an Xnest (typically, the Metacity under the Xnest
|
||||
wouldn't get keybinding notifications--making keyboard navigation not
|
||||
work--but if you disable the keybindings for the global Metacity then
|
||||
the Metacity under the Xnest can then get those keybinding notifications).
|
||||
|
||||
metacity-window-demo
|
||||
metacity-window-demo is good for trying behavior of various kinds
|
||||
of window without launching a full desktop.
|
||||
|
||||
Technical gotchas to keep in mind
|
||||
Files that include gdk.h or gtk.h are not supposed to include
|
||||
display.h or window.h or other core files. Files in the core
|
||||
(display.[hc], window.[hc]) are not supposed to include gdk.h or
|
||||
gtk.h. Reasons:
|
||||
|
||||
"Basically you don't want GDK most of the time. It adds
|
||||
abstractions that cause problems, because they aren't designed to
|
||||
be used in a WM where we do weird stuff (display grabs, and just
|
||||
being the WM). At best GDK adds inefficiency, at worst it breaks
|
||||
things in weird ways where you have to be a GDK guru to figure
|
||||
them out. Owen also told me that they didn't want to start adding
|
||||
a lot of hacks to GDK to let a WM use it; we both agreed back in
|
||||
the mists of time that metacity would only use it for the "UI"
|
||||
bits as it does.
|
||||
|
||||
Having the split in the source code contains and makes very clear
|
||||
the interface between the WM and GDK/GTK. This keeps people from
|
||||
introducing extra GDK/GTK usage when it isn't needed or
|
||||
appropriate. Also, it speeds up the compilation a bit, though this
|
||||
was perhaps more relevant 5 years ago than it is now.
|
||||
|
||||
There was also a very old worry that the GDK stuff might have to
|
||||
be in a separate process to work right; that turned out to be
|
||||
untrue. Though who knows what issues the CM will introduce."
|
||||
|
||||
Remember that strings stored in X properties are not in UTF-8, and they
|
||||
have to end up in UTF-8 before we try putting them through Pango.
|
||||
|
||||
If you make any X request involving a client window, you have to
|
||||
meta_error_trap_push() around the call; this is not necessary for X
|
||||
requests on the frame windows.
|
||||
|
||||
Remember that not all windows have frames, and window->frame can be NULL.
|
||||
|
||||
Other important reading & where to get started
|
||||
Extra reading
|
||||
|
||||
There are some other important things to read to get oriented as well.
|
||||
These are:
|
||||
http://pobox.com/~hp/features.html
|
||||
rationales.txt
|
||||
doc/code-overview.txt
|
||||
|
||||
It pays to read http://pobox.com/~hp/features.html in order
|
||||
to understand the philosophy of Metacity.
|
||||
|
||||
The rationales.txt file has two things: (1) a list of design choices with
|
||||
links in the form of bugzilla bugs that discuss the issue, and (2) a list
|
||||
outstanding bug categories, each of which is tracked by a particular
|
||||
tracker bug in bugzilla from which you can find several closely related
|
||||
bug reports.
|
||||
|
||||
doc/code-overview.txt provides a fairly good overview of the code,
|
||||
including coverage of the function of the various files, the main
|
||||
structures and their relationships, and places to start looking in the
|
||||
code tailored to general categories of tasks.
|
||||
|
||||
Ideas for tasks to work on
|
||||
|
||||
There are a variety of things you could work on in the code. You may
|
||||
have ideas of your own, but in case you don't, let me provide a list of
|
||||
ideas you could choose from:
|
||||
|
||||
If you're ambitious, there's a list of things Havoc made that he'd really
|
||||
like to see tackled, which you can find at
|
||||
http://log.ometer.com/2004-05.html. Be sure to double check with someone
|
||||
to make sure the item is still relevant if you're interested in one of
|
||||
these. Another place to look for ideas, of course, is bugzilla. One can
|
||||
just do queries and look for things that look fixable.
|
||||
|
||||
However, perhaps the best way of getting ideas of related tasks to work
|
||||
on, is to look at the second half of the rationales.txt file, which tries
|
||||
to group bugs by type.
|
@@ -1,8 +0,0 @@
|
||||
Tomas Frydrych
|
||||
Email: tf linux intel com
|
||||
Userid: tomasf
|
||||
|
||||
Owen Taylor
|
||||
Email: otaylor redhat com
|
||||
Userid: otaylor
|
||||
|
@@ -1,43 +0,0 @@
|
||||
Currently active maintainers
|
||||
--------------------------------
|
||||
|
||||
Elijah Newren
|
||||
Email: newren gmail com
|
||||
Userid: newren
|
||||
|
||||
- Usually won't touch the theme bugs (isn't interested) or the
|
||||
compositor (until open source nvidia drivers are up to snuff).
|
||||
Tends to be most interested in libwnck/gtk interactions, focus
|
||||
issues, constraints problems, and raising/stacking, but works on
|
||||
just about anything other than themes and the compositor.
|
||||
|
||||
Thomas Thurman
|
||||
Email: thomas thurman org uk
|
||||
Userid: tthurman
|
||||
|
||||
- Responsible for all theme bugs and the compositor (thank goodness
|
||||
Thomas got involved, eh?). I'm sure he'll replace this sentence
|
||||
with his interests when he reads it. ;-)
|
||||
|
||||
|
||||
Semi-active maintainers
|
||||
--------------------------------
|
||||
|
||||
Havoc Pennington
|
||||
Email: hp redhat com
|
||||
Userid: hp
|
||||
- Original author. Doesn't patch metacity anymore, but is active in
|
||||
answering questions, responding to bugs, providing very helpful
|
||||
suggestions and insight, and even assisting with debugging.
|
||||
|
||||
|
||||
Important historical figureheads
|
||||
--------------------------------
|
||||
|
||||
Rob Adams (readams readams net)
|
||||
- Was the main maintainer of metacity for a while; particular areas
|
||||
of focus included xinerama, placement, and an older version of the
|
||||
constraints code. Still responds to bugs every once in a while.
|
||||
|
||||
Søren Sandmann (sandmann redhat com)
|
||||
- Wrote most of the current compositing manager code + libcm
|
@@ -1,7 +1,5 @@
|
||||
|
||||
SUBDIRS=src protocol po doc
|
||||
|
||||
EXTRA_DIST = HACKING MAINTAINERS rationales.txt
|
||||
SUBDIRS=src po doc
|
||||
|
||||
DISTCLEANFILES = intltool-extract intltool-merge intltool-update po/stamp-it po/.intltool-merge-cache
|
||||
|
||||
|
11
NEWS
11
NEWS
@@ -1,3 +1,14 @@
|
||||
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]
|
||||
|
416
README
416
README
@@ -1,416 +0,0 @@
|
||||
The original codebase named "Metacity" is not a meta-City as in an
|
||||
urban center, but rather Meta-ness as in the state of being
|
||||
meta. i.e. metacity : meta as opacity : opaque. Also it may have
|
||||
something to do with the Meta key on UNIX keyboards.
|
||||
|
||||
Since then, it has been renamed mutter after a rebase on top of
|
||||
clutter as a compositing manager.
|
||||
|
||||
COMPILING MUTTER
|
||||
===
|
||||
|
||||
You need GTK+ 2.2. For startup notification to work you need
|
||||
libstartup-notification at
|
||||
http://www.freedesktop.org/software/startup-notification/ or on the
|
||||
GNOME ftp site.
|
||||
You need Clutter 1.0. You need gobject-introspection 0.6.3.
|
||||
|
||||
REPORTING BUGS AND SUBMITTING PATCHES
|
||||
===
|
||||
|
||||
Report new bugs on http://bugzilla.gnome.org. Please check for
|
||||
duplicates, *especially* if you are reporting a feature request.
|
||||
|
||||
Please do *not* add "me too!" or "yes I really want this!" comments to
|
||||
feature requests in bugzilla. Please read
|
||||
http://pobox.com/~hp/features.html prior to adding any kind of flame
|
||||
about missing features or misfeatures.
|
||||
|
||||
Feel free to send patches too; Metacity is relatively small and
|
||||
simple, so if you find a bug or want to add a feature it should be
|
||||
pretty easy. Send me mail, or put the patch in bugzilla.
|
||||
|
||||
See the HACKING file for some notes on hacking Mutter.
|
||||
|
||||
MUTTER FEATURES
|
||||
===
|
||||
|
||||
- Uses GTK+ 2.0 for drawing window frames. This means colors, fonts,
|
||||
etc. come from GTK+ theme.
|
||||
|
||||
- Does not expose the concept of "window manager" to the user. Some
|
||||
of the features in the GNOME control panel and other parts of the
|
||||
desktop happen to be implemented in metacity, such as changing your
|
||||
window border theme, or changing your window navigation shortcuts,
|
||||
but the user doesn't need to know this.
|
||||
|
||||
- Includes only the window manager; does not try to be a desktop
|
||||
environment. The pager, configuration, etc. are all separate and
|
||||
modular. The "libwnck" library (which I also wrote) is available
|
||||
for writing metacity extensions, pagers, and so on. (But libwnck
|
||||
isn't metacity specific, or GNOME-dependent; it requires only GTK,
|
||||
and should work with KWin, fvwm2, and other EWMH-compliant WMs.)
|
||||
|
||||
- Has a simple theme system and a couple of extra themes come with it.
|
||||
Change themes via gsettings:
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Crux
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Gorilla
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Atlanta
|
||||
gsettings set org.gnome.desktop.wm.preferences theme Bright
|
||||
|
||||
See theme-format.txt for docs on the theme format. Use
|
||||
metacity-theme-viewer to preview themes.
|
||||
|
||||
- Change number of workspaces via gsettings:
|
||||
gsettings set org.gnome.desktop.wm.preferences num-workspaces 5
|
||||
|
||||
Can also change workspaces from GNOME 2 pager.
|
||||
|
||||
- Change focus mode:
|
||||
gsettings set org.gnome.desktop.wm.preferences focus-mode mouse
|
||||
gsettings set org.gnome.desktop.wm.preferences focus-mode sloppy
|
||||
gsettings set org.gnome.desktop.wm.preferences focus-mode click
|
||||
|
||||
- Global keybinding defaults include:
|
||||
|
||||
Alt-Tab forward cycle window focus
|
||||
Alt-Shift-Tab backward cycle focus
|
||||
Alt-Ctrl-Tab forward cycle focus among panels
|
||||
Alt-Ctrl-Shift-Tab backward cycle focus among panels
|
||||
Alt-Escape cycle window focus without a popup thingy
|
||||
Ctrl-Alt-Left Arrow previous workspace
|
||||
Ctrl-Alt-Right Arrow next workspace
|
||||
Ctrl-Alt-D minimize/unminimize all, to show desktop
|
||||
|
||||
Change keybindings for example:
|
||||
|
||||
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 '[<Alt>F1]'
|
||||
|
||||
Also try the GNOME keyboard shortcuts control panel.
|
||||
|
||||
- Window keybindings:
|
||||
|
||||
Alt-space window menu
|
||||
|
||||
Mnemonics work in the menu. That is, Alt-space then underlined
|
||||
letter in the menu item works.
|
||||
|
||||
Choose Move from menu, and arrow keys to move the window.
|
||||
|
||||
While moving, hold down Control to move slower, and
|
||||
Shift to snap to edges.
|
||||
|
||||
Choose Resize from menu, and nothing happens yet, but
|
||||
eventually I might implement something.
|
||||
|
||||
Keybindings for things like maximize window, vertical maximize,
|
||||
etc. can be bound, but may not all exist by default. See
|
||||
metacity.schemas.
|
||||
|
||||
- Window mouse bindings:
|
||||
|
||||
Clicking anywhere on frame with button 1 will raise/focus window
|
||||
|
||||
If you click a window control, such as the close button, then the
|
||||
control will activate on button release if you are still over it
|
||||
on release (as with most GUI toolkits)
|
||||
|
||||
If you click and drag borders with button 1 it resizes the window
|
||||
|
||||
If you click and drag the titlebar with button 1 it moves the
|
||||
window.
|
||||
|
||||
If you click anywhere on the frame with button 2 it lowers the
|
||||
window.
|
||||
|
||||
If you click anywhere on the frame with button 3 it shows the
|
||||
window menu.
|
||||
|
||||
If you hold down Super (windows key) and click inside a window, it
|
||||
will move the window (buttons 1 and 2) or show menu (button 3).
|
||||
Or you can configure a different modifier for this.
|
||||
|
||||
If you pick up a window with button 1 and then switch workspaces
|
||||
the window will come with you to the new workspace, this is
|
||||
a feature copied from Enlightenment.
|
||||
|
||||
If you hold down Shift while moving a window, the window snaps
|
||||
to edges of other windows and the screen.
|
||||
|
||||
- Session management:
|
||||
|
||||
Mutter connects to the session manager and will set itself up to
|
||||
be respawned. It theoretically restores sizes/positions/workspace
|
||||
for session-aware applications.
|
||||
|
||||
- Mutter implements much of the EWMH window manager specification
|
||||
from freedesktop.org, as well as the older ICCCM. Please refer to
|
||||
the COMPLIANCE file for information on mutter compliance with
|
||||
these standards.
|
||||
|
||||
- Uses Pango to render text, so has cool i18n capabilities.
|
||||
Supports UTF-8 window titles and such.
|
||||
|
||||
- There are simple animations for actions such as minimization,
|
||||
to help users see what is happening. Should probably
|
||||
have a few more of these and make them nicer.
|
||||
|
||||
- if you have the proper X setup, set the GDK_USE_XFT=1
|
||||
environment variable to get antialiased window titles.
|
||||
|
||||
- considers the panel when placing windows and maximizing
|
||||
them.
|
||||
|
||||
- handles the window manager selection from the ICCCM. Will exit if
|
||||
another WM claims it, and can claim it from another WM if you pass
|
||||
the --replace argument. So if you're running another
|
||||
ICCCM-compliant WM, you can run "mutter --replace" to replace it
|
||||
with Metacity.
|
||||
|
||||
- does basic colormap handling
|
||||
|
||||
- and much more! well, maybe not a lot more.
|
||||
|
||||
HOW TO ADD EXTERNAL FEATURES
|
||||
===
|
||||
|
||||
You can write a mutter "plugin" such as a pager, window list, icon
|
||||
box, task menu, or even things like "window matching" using the
|
||||
Extended Window Manager Hints. See http://www.freedesktop.org for the
|
||||
EWMH specification. An easy-to-use library called "libwnck" is
|
||||
available that uses the EWMH and is specifically designed for writing
|
||||
WM accessories.
|
||||
|
||||
You might be interested in existing accessories such as "Devil's Pie"
|
||||
by Ross Burton, which add features to Mutter (or other
|
||||
EWMH-compliant WMs).
|
||||
|
||||
MUTTER BUGS, NON-FEATURES, AND CAVEATS
|
||||
===
|
||||
|
||||
See bugzilla: http://bugzilla.gnome.org/query.cgi
|
||||
|
||||
FAQ
|
||||
===
|
||||
|
||||
Q: Will you add my feature?
|
||||
|
||||
A: If it makes sense to turn on unconditionally, or is genuinely a
|
||||
harmless preference that I would not be embarrassed to put in a
|
||||
simple, uncluttered, user-friendly configuration dialog.
|
||||
|
||||
If the only rationale for your feature is that other window
|
||||
managers have it, or that you are personally used to it, or
|
||||
something like that, then I will not be impressed. Metacity is
|
||||
firmly in the "choose good defaults" camp rather than the "offer 6
|
||||
equally broken ways to do it, and let the user pick one" camp.
|
||||
|
||||
This is part of a "no crackrock" policy, despite some exceptions
|
||||
I'm mildly embarrassed about. For example, multiple workspaces
|
||||
probably constitute crackrock, they confuse most users and really
|
||||
are not that useful if you have a decent tasklist and so on. But I
|
||||
am too used to them to turn them off. Or alternatively
|
||||
iconification/tasklist is crack, and workspaces/pager are good. But
|
||||
having both is certainly a bit wrong. Sloppy focus is probably
|
||||
crackrock too.
|
||||
|
||||
But don't think unlimited crack is OK just because I slipped up a
|
||||
little. No slippery slope here.
|
||||
|
||||
Don't let this discourage patches and fixes - I love those. ;-)
|
||||
Just be prepared to hear the above objections if your patch adds
|
||||
some crack-ridden configuration option.
|
||||
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Will Mutter be part of GNOME?
|
||||
|
||||
A: It is not officially part of GNOME as of GNOME 2.27. We are
|
||||
hoping to have mutter officially included as of GNOME 2.28.
|
||||
|
||||
Q: Why does Mutter remember the workspace/position of some apps
|
||||
but not others across logout/login?
|
||||
|
||||
A: Mutter only stores sizes/positions for apps that are session
|
||||
managed. As far as I can determine, there is no way to attempt to
|
||||
remember workspace/position for non-session-aware apps without
|
||||
causing a lot of weird effects.
|
||||
|
||||
The reason is that you don't know which non-SM-aware apps were
|
||||
launched by the session. When you initially log in, Metacity sees a
|
||||
bunch of new windows appear. But it can't distinguish between
|
||||
windows that were stored in your session, or windows you just
|
||||
launched after logging in. If Metacity tried to guess that a window
|
||||
was from the session, it could e.g. end up maximizing a dialog, or
|
||||
put a window you just launched on another desktop or in a weird
|
||||
place. And in fact I see a lot of bugs like this in window managers
|
||||
that try to handle non-session-aware apps.
|
||||
|
||||
However, for session-aware apps, Mutter can tell that the
|
||||
application instance is from the session and thus restore it
|
||||
reliably, assuming the app properly restores the windows it had
|
||||
open on session save.
|
||||
|
||||
So the correct way to fix the situation is to make apps
|
||||
session-aware. libSM has come with X for years, it's very
|
||||
standardized, it's shared by GNOME and KDE - even twm is
|
||||
session-aware. So anyone who won't take a patch to add SM is more
|
||||
archaic than twm - and you should flame them. ;-)
|
||||
|
||||
Docs on session management:
|
||||
http://www.fifi.org/doc/xspecs/xsmp.txt.gz
|
||||
http://www.fifi.org/doc/xspecs/SMlib.txt.gz
|
||||
|
||||
See also the ICCCM section on SM. For GNOME apps, use the
|
||||
GnomeClient object. For a simple example of using libSM directly,
|
||||
twm/session.c in the twm source code is pretty easy to understand.
|
||||
|
||||
Q: How about adding viewports in addition to workspaces?
|
||||
|
||||
A: I could conceivably be convinced to use viewports _instead_ of
|
||||
workspaces, though currently I'm not thinking that. But I don't
|
||||
think it makes any sense to have both; it's just confusing. They
|
||||
are functionally equivalent.
|
||||
|
||||
You may think this means that you won't have certain keybindings,
|
||||
or something like that. This is a misconception. The only
|
||||
_fundamental_ difference between viewports and workspaces is that
|
||||
with viewports, windows can "overlap" and appear partially on
|
||||
one and partially on another. All other differences that
|
||||
traditionally exist in other window managers are accidental -
|
||||
the features commonly associated with viewports can be implemented
|
||||
for workspaces, and vice versa.
|
||||
|
||||
So I don't want to have two kinds of
|
||||
workspace/desktop/viewport/whatever, but I'm willing to add
|
||||
features traditionally associated with either kind if those
|
||||
features make sense.
|
||||
|
||||
Q: Why is the panel always on top?
|
||||
|
||||
A: Because it's a better user interface, and until we made this not
|
||||
configurable a bunch of apps were not getting fixed (the app
|
||||
authors were just saying "put your panel on the bottom" instead of
|
||||
properly supporting fullscreen mode, and such).
|
||||
|
||||
rationales.txt has the bugzilla URL for some flamefesting on this,
|
||||
if you want to go back and relive the glory.
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Why is there no edge flipping?
|
||||
|
||||
A: This one is also in rationales.txt. Because "ouija board" UI, where
|
||||
you just move the mouse around and the computer guesses what you
|
||||
mean, has a lot of issues. This includes mouse focus, shade-hover
|
||||
mode, edge flipping, autoraise, etc. Metacity has mouse focus and
|
||||
autoraise as a compromise, but these features are all confusing for
|
||||
many users, and cause problems with accessibility, fitt's law, and
|
||||
so on.
|
||||
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
Q: Why does wireframe move/resize suck?
|
||||
|
||||
A: You can turn it on with the reduced_resources setting.
|
||||
|
||||
But: it has low usability, and is a pain
|
||||
to implement, and there's no reason opaque move/resize should be a
|
||||
problem on any setup that can run a modern desktop worth a darn to
|
||||
begin with.
|
||||
|
||||
Read these and the bugzilla stuff before asking/commenting:
|
||||
http://pobox.com/~hp/free-software-ui.html
|
||||
http://pobox.com/~hp/features.html
|
||||
|
||||
The reason we had to add wireframe anyway was broken
|
||||
proprietary apps that can't handle lots of resize events.
|
||||
|
||||
Q: Why no XYZ?
|
||||
|
||||
A: You are probably getting the idea by now - check rationales.txt,
|
||||
query/search bugzilla, and read http://pobox.com/~hp/features.html
|
||||
and http://pobox.com/~hp/free-software-ui.html
|
||||
|
||||
Then sit down and answer the question for yourself. Is the feature
|
||||
good? What's the rationale for it? Answer "why" not just "why not."
|
||||
Justify in terms of users as a whole, not just users like
|
||||
yourself. How else can you solve the same problem? etc. If that
|
||||
leads you to a strong opinion, then please, post the rationale for
|
||||
discussion to an appropriate bugzilla bug, or to
|
||||
usability@gnome.org.
|
||||
|
||||
Please don't just "me too!" on bugzilla bugs, please don't think
|
||||
flames will get you anywhere, and please don't repeat rationale
|
||||
that's already been offered.
|
||||
|
||||
Q: Your dumb web pages you made me read talk about solving problems in
|
||||
fundamental ways instead of adding preferences or workarounds.
|
||||
What are some examples where metacity has done this?
|
||||
|
||||
A: There are quite a few, though many opportunities remain. Sometimes
|
||||
the real fix involves application changes. The metacity approach is
|
||||
that it's OK to require apps to change, though there are also
|
||||
plenty of workarounds in metacity for battles considered too hard
|
||||
to fight.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- fullscreen mode was introduced to allow position constraints,
|
||||
panel-on-top, and other such things to apply to normal windows
|
||||
while still allowing video players etc. to "just work"
|
||||
|
||||
- "whether to include minimized windows in Alt+Tab" was solved
|
||||
by putting minimized windows at the *end* of the tab order.
|
||||
|
||||
- Whether to pop up a feedback display during Alt+Tab was solved by
|
||||
having both Alt+Tab and Alt+Esc
|
||||
|
||||
- Whether to have a "kill" feature was solved by automatically
|
||||
detecting and offering to kill stuck apps. Better, metacity
|
||||
actually does "kill -9" on the process, it doesn't just
|
||||
disconnect the process from the X server. You'll appreciate this
|
||||
if you ever did a "kill" on Netscape 4, and watched it keep
|
||||
eating 100% CPU even though the X server had booted it.
|
||||
|
||||
- The workspaces vs. viewports mess was avoided by adding
|
||||
directional navigation and such to workspaces, see discussion
|
||||
earlier in this file.
|
||||
|
||||
- Instead of configurable placement algorithms, there's just one
|
||||
that works fairly well most of the time.
|
||||
|
||||
- To avoid excess CPU use during opaque move/resize, we rate limit
|
||||
the updates to the application window's size.
|
||||
|
||||
- Instead of configurable "show size of window while resizing,"
|
||||
it's only shown for windows where it matters, such as terminals.
|
||||
(Only use-case given for all windows is for web designers
|
||||
choosing their web browser size, but there are web sites and
|
||||
desktop backgrounds that do this for you.)
|
||||
|
||||
- Using startup notification, applications open on the workspace
|
||||
where you launched them, not the active workspace when their
|
||||
window is opened.
|
||||
|
||||
- and much more.
|
||||
|
||||
Q: I think mutter sucks.
|
||||
|
||||
A: Feel free to use any WM you like. The reason metacity follows the
|
||||
ICCCM and EWMH specifications is that it makes metacity a modular,
|
||||
interchangeable part in the desktop. libwnck-based apps such as the
|
||||
GNOME window list will work just fine with any EWMH-compliant WM.
|
||||
|
||||
Q: Did you spend a lot of time on this?
|
||||
|
||||
A: Originally the answer was no. Sadly the answer is now yes.
|
||||
|
||||
Q: How can you claim that you are anti-crack, while still
|
||||
writing a window manager?
|
||||
|
||||
A: I have no comment on that.
|
@@ -5,7 +5,7 @@ srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
PKG_NAME="mutter"
|
||||
REQUIRED_AUTOMAKE_VERSION=1.13
|
||||
REQUIRED_AUTOMAKE_VERSION=1.10
|
||||
|
||||
(test -f $srcdir/configure.ac \
|
||||
&& test -d $srcdir/src) || {
|
||||
|
@@ -3,7 +3,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
m4_define([mutter_major_version], [3])
|
||||
m4_define([mutter_minor_version], [11])
|
||||
m4_define([mutter_micro_version], [91])
|
||||
m4_define([mutter_micro_version], [92])
|
||||
|
||||
m4_define([mutter_version],
|
||||
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
||||
@@ -140,6 +140,7 @@ AM_GLIB_GNU_GETTEXT
|
||||
## here we get the flags we'll actually use
|
||||
# GRegex requires Glib-2.14.0
|
||||
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
|
||||
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
|
||||
|
||||
# Unconditionally use this dir to avoid a circular dep with gnomecc
|
||||
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
|
||||
@@ -212,7 +213,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm libsystemd"
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm"
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||
@@ -452,7 +453,6 @@ doc/reference/meta-docs.sgml
|
||||
src/Makefile
|
||||
src/libmutter-wayland.pc
|
||||
src/compositor/plugins/Makefile
|
||||
protocol/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = man reference
|
||||
|
||||
EXTRA_DIST=theme-format.txt dialogs.txt code-overview.txt \
|
||||
how-to-get-focus-right.txt
|
||||
how-to-get-focus-right.txt rationales.txt
|
||||
|
@@ -16,11 +16,11 @@ src/core/monitor.c
|
||||
src/core/mutter.c
|
||||
src/core/prefs.c
|
||||
src/core/screen.c
|
||||
src/core/session.c
|
||||
src/x11/session.c
|
||||
src/core/util.c
|
||||
src/core/window.c
|
||||
src/core/window-props.c
|
||||
src/core/xprops.c
|
||||
src/x11/window-props.c
|
||||
src/x11/xprops.c
|
||||
src/mutter-wayland.desktop.in
|
||||
src/org.gnome.mutter.gschema.xml.in
|
||||
src/org.gnome.mutter.wayland.gschema.xml.in
|
||||
|
@@ -1,7 +0,0 @@
|
||||
NULL =
|
||||
|
||||
EXTRA_DIST = \
|
||||
gtk-shell.xml \
|
||||
xdg-shell.xml \
|
||||
xserver.xml \
|
||||
$(NULL)
|
@@ -29,29 +29,28 @@ INCLUDES= \
|
||||
-DMUTTER_PLUGIN_API_VERSION=$(MUTTER_PLUGIN_API_VERSION) \
|
||||
-DMUTTER_PKGLIBDIR=\"$(pkglibdir)\" \
|
||||
-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \
|
||||
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
|
||||
|
||||
INCLUDES += \
|
||||
-I$(srcdir)/wayland \
|
||||
-I$(builddir)/wayland \
|
||||
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
|
||||
-DXWAYLAND_PATH='"@XWAYLAND_PATH@"'
|
||||
|
||||
mutter_built_sources = \
|
||||
$(dbus_idle_built_sources) \
|
||||
$(dbus_xrandr_built_sources) \
|
||||
$(dbus_login1_built_sources) \
|
||||
mutter-enum-types.h \
|
||||
mutter-enum-types.c \
|
||||
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
|
||||
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
|
||||
|
||||
libmutter_wayland_la_SOURCES = \
|
||||
core/async-getprop.c \
|
||||
core/async-getprop.h \
|
||||
core/above-tab-keycode.c \
|
||||
core/barrier.c \
|
||||
meta/barrier.h \
|
||||
core/bell.c \
|
||||
@@ -106,7 +105,6 @@ 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 \
|
||||
@@ -124,13 +122,6 @@ libmutter_wayland_la_SOURCES = \
|
||||
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 \
|
||||
@@ -153,8 +144,6 @@ 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 \
|
||||
@@ -162,22 +151,20 @@ 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 \
|
||||
ui/frames.c \
|
||||
ui/frames.h \
|
||||
ui/menu.c \
|
||||
ui/menu.h \
|
||||
ui/metaaccellabel.c \
|
||||
ui/metaaccellabel.h \
|
||||
ui/resizepopup.c \
|
||||
ui/resizepopup.h \
|
||||
ui/theme-parser.c \
|
||||
@@ -185,6 +172,24 @@ libmutter_wayland_la_SOURCES = \
|
||||
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 \
|
||||
@@ -204,8 +209,8 @@ libmutter_wayland_la_SOURCES = \
|
||||
wayland/meta-wayland-surface.h \
|
||||
wayland/meta-wayland-types.h \
|
||||
wayland/meta-wayland-versions.h \
|
||||
wayland/meta-login1.c \
|
||||
wayland/meta-login1.h
|
||||
wayland/meta-weston-launch.c \
|
||||
wayland/meta-weston-launch.h
|
||||
|
||||
nodist_libmutter_wayland_la_SOURCES = \
|
||||
$(mutter_built_sources)
|
||||
@@ -260,6 +265,17 @@ bin_PROGRAMS=mutter-wayland
|
||||
mutter_wayland_SOURCES = core/mutter.c
|
||||
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
||||
|
||||
bin_PROGRAMS+=mutter-launch
|
||||
|
||||
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
|
||||
|
||||
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
|
||||
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
|
||||
|
||||
install-exec-hook:
|
||||
-chown root $(DESTDIR)$(bindir)/mutter-launch
|
||||
-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
include $(INTROSPECTION_MAKEFILE)
|
||||
|
||||
@@ -295,7 +311,7 @@ endif
|
||||
|
||||
testboxes_SOURCES = core/testboxes.c
|
||||
testgradient_SOURCES = ui/testgradient.c
|
||||
testasyncgetprop_SOURCES = core/testasyncgetprop.c
|
||||
testasyncgetprop_SOURCES = x11/testasyncgetprop.c
|
||||
|
||||
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
|
||||
|
||||
@@ -346,6 +362,7 @@ 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 \
|
||||
@@ -395,18 +412,7 @@ $(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
|
||||
--c-generate-object-manager \
|
||||
$(srcdir)/idle-monitor.xml
|
||||
|
||||
dbus_login1_built_sources = meta-dbus-login1.c meta-dbus-login1.h
|
||||
|
||||
$(dbus_login1_built_sources) : Makefile.am org.freedesktop.login1.xml
|
||||
$(AM_V_GEN)gdbus-codegen \
|
||||
--interface-prefix org.freedesktop.login1 \
|
||||
--c-namespace Login1 \
|
||||
--generate-c-code meta-dbus-login1 \
|
||||
$(srcdir)/org.freedesktop.login1.xml
|
||||
|
||||
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
|
||||
mkdir -p wayland
|
||||
%-protocol.c : $(srcdir)/wayland/protocol/%.xml
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
|
||||
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
|
||||
mkdir -p wayland
|
||||
%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
|
||||
|
@@ -19,16 +19,10 @@ 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;
|
||||
};
|
||||
|
||||
@@ -36,10 +30,9 @@ struct _MetaCompScreen
|
||||
{
|
||||
MetaScreen *screen;
|
||||
|
||||
ClutterActor *stage, *window_group, *top_window_group, *overlay_group;
|
||||
ClutterActor *stage, *window_group, *top_window_group;
|
||||
ClutterActor *background_actor;
|
||||
GList *windows;
|
||||
GHashTable *windows_by_xid;
|
||||
Window output;
|
||||
|
||||
CoglOnscreen *onscreen;
|
||||
@@ -70,6 +63,4 @@ 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 */
|
||||
|
@@ -65,7 +65,6 @@
|
||||
#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>
|
||||
@@ -77,14 +76,16 @@
|
||||
#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>
|
||||
|
||||
/* #define DEBUG_TRACE g_print */
|
||||
#define DEBUG_TRACE(X)
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
|
||||
static gboolean
|
||||
is_modal (MetaDisplay *display)
|
||||
{
|
||||
return display->grab_op == META_GRAB_OP_COMPOSITOR;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
composite_at_least_version (MetaDisplay *display, int maj, int min)
|
||||
@@ -109,13 +110,8 @@ 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 in case the plugin messed it up.
|
||||
*/
|
||||
/* Fix up stacking order. */
|
||||
sync_actor_stacking (info);
|
||||
|
||||
/* printf ("... FINISHED DESKTOP SWITCH\n"); */
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -141,33 +137,12 @@ meta_compositor_destroy (MetaCompositor *compositor)
|
||||
clutter_threads_remove_repaint_func (compositor->repaint_func_id);
|
||||
}
|
||||
|
||||
static void
|
||||
add_win (MetaWindow *window)
|
||||
{
|
||||
MetaScreen *screen = meta_window_get_screen (window);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
meta_window_actor_new (window);
|
||||
|
||||
sync_actor_stacking (info);
|
||||
}
|
||||
|
||||
static void
|
||||
process_damage (MetaCompositor *compositor,
|
||||
XDamageNotifyEvent *event,
|
||||
MetaWindow *window)
|
||||
{
|
||||
MetaWindowActor *window_actor;
|
||||
|
||||
if (window == NULL)
|
||||
return;
|
||||
|
||||
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
if (window_actor == NULL)
|
||||
return;
|
||||
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
meta_window_actor_process_x11_damage (window_actor, event);
|
||||
}
|
||||
|
||||
@@ -372,7 +347,6 @@ 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;
|
||||
@@ -392,7 +366,7 @@ begin_modal_x11 (MetaScreen *screen,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
grab_window,
|
||||
timestamp,
|
||||
cursor,
|
||||
None,
|
||||
XIGrabModeAsync, XIGrabModeAsync,
|
||||
False, /* owner_events */
|
||||
&mask);
|
||||
@@ -446,11 +420,10 @@ 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);
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
gboolean ok;
|
||||
|
||||
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
|
||||
if (is_modal (display) || display->grab_op != META_GRAB_OP_NONE)
|
||||
return FALSE;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
@@ -466,8 +439,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
display->grab_have_pointer = TRUE;
|
||||
display->grab_have_keyboard = TRUE;
|
||||
|
||||
compositor->modal_plugin = plugin;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -476,11 +447,10 @@ 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);
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdpy = meta_display_get_xdisplay (display);
|
||||
|
||||
g_return_if_fail (compositor->modal_plugin == plugin);
|
||||
g_return_if_fail (is_modal (display));
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
@@ -493,27 +463,6 @@ meta_end_modal_for_plugin (MetaScreen *screen,
|
||||
display->grab_screen = NULL;
|
||||
display->grab_have_pointer = FALSE;
|
||||
display->grab_have_keyboard = FALSE;
|
||||
|
||||
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_end_modal_for_plugin (screen,
|
||||
compositor->modal_plugin,
|
||||
|
||||
CurrentTime);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -715,18 +664,25 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shapes the cow so that the given window is exposed,
|
||||
* when metaWindow is NULL it clears the shape again
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
meta_shape_cow_for_window (MetaScreen *screen,
|
||||
MetaWindow *metaWindow)
|
||||
MetaWindow *window)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (meta_screen_get_display (screen));
|
||||
|
||||
if (metaWindow == NULL)
|
||||
if (window == NULL)
|
||||
XFixesSetWindowShapeRegion (xdisplay, info->output, ShapeBounding, 0, 0, None);
|
||||
else
|
||||
{
|
||||
@@ -735,7 +691,7 @@ meta_shape_cow_for_window (MetaScreen *screen,
|
||||
int width, height;
|
||||
MetaRectangle rect;
|
||||
|
||||
meta_window_get_frame_rect (metaWindow, &rect);
|
||||
meta_window_get_frame_rect (window, &rect);
|
||||
|
||||
window_bounds.x = rect.x;
|
||||
window_bounds.y = rect.y;
|
||||
@@ -786,11 +742,12 @@ meta_compositor_add_window (MetaCompositor *compositor,
|
||||
{
|
||||
MetaScreen *screen = meta_window_get_screen (window);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
DEBUG_TRACE ("meta_compositor_add_window\n");
|
||||
meta_error_trap_push (display);
|
||||
|
||||
add_win (window);
|
||||
meta_window_actor_new (window);
|
||||
sync_actor_stacking (info);
|
||||
|
||||
meta_error_trap_pop (display);
|
||||
}
|
||||
@@ -799,17 +756,9 @@ void
|
||||
meta_compositor_remove_window (MetaCompositor *compositor,
|
||||
MetaWindow *window)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
|
||||
if (info->unredirected_window == window)
|
||||
set_unredirected_window (info, NULL);
|
||||
@@ -822,13 +771,7 @@ meta_compositor_set_updates_frozen (MetaCompositor *compositor,
|
||||
MetaWindow *window,
|
||||
gboolean updates_frozen)
|
||||
{
|
||||
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;
|
||||
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
meta_window_actor_set_updates_frozen (window_actor, updates_frozen);
|
||||
}
|
||||
|
||||
@@ -837,13 +780,7 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor,
|
||||
MetaWindow *window,
|
||||
gboolean no_delay_frame)
|
||||
{
|
||||
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;
|
||||
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame);
|
||||
}
|
||||
|
||||
@@ -1023,9 +960,9 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
|
||||
info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (compositor->modal_plugin && is_grabbed_event (compositor->display, event))
|
||||
if (is_modal (display) && is_grabbed_event (compositor->display, event))
|
||||
{
|
||||
_meta_plugin_xevent_filter (compositor->modal_plugin, event);
|
||||
meta_plugin_manager_xevent_filter (info->plugin_mgr, event);
|
||||
|
||||
/* We always consume events even if the plugin says it didn't handle them;
|
||||
* exclusive is exclusive */
|
||||
@@ -1036,10 +973,7 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
maybe_spoof_event_as_stage_event (info, window, event);
|
||||
|
||||
if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
|
||||
{
|
||||
DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
|
||||
return TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
if (!meta_is_wayland_compositor () &&
|
||||
event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
@@ -1053,7 +987,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1075,11 +1008,7 @@ meta_compositor_filter_keybinding (MetaCompositor *compositor,
|
||||
MetaKeyBinding *binding)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (info->plugin_mgr)
|
||||
return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding);
|
||||
|
||||
return FALSE;
|
||||
return meta_plugin_manager_filter_keybinding (info->plugin_mgr, binding);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1088,11 +1017,7 @@ meta_compositor_show_window (MetaCompositor *compositor,
|
||||
MetaCompEffect effect)
|
||||
{
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
DEBUG_TRACE ("meta_compositor_show_window\n");
|
||||
if (!window_actor)
|
||||
return;
|
||||
|
||||
meta_window_actor_show (window_actor, effect);
|
||||
meta_window_actor_show (window_actor, effect);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1101,10 +1026,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1115,10 +1036,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1129,10 +1046,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1150,18 +1063,14 @@ 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 (!info->plugin_mgr ||
|
||||
!meta_plugin_manager_switch_workspace (info->plugin_mgr,
|
||||
from_indx,
|
||||
to_indx,
|
||||
direction))
|
||||
if (!meta_plugin_manager_switch_workspace (info->plugin_mgr,
|
||||
from_indx, to_indx,
|
||||
direction))
|
||||
{
|
||||
info->switch_workspace_in_progress--;
|
||||
|
||||
@@ -1270,8 +1179,6 @@ 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
|
||||
@@ -1360,15 +1267,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1400,7 +1298,6 @@ 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);
|
||||
@@ -1704,10 +1601,6 @@ meta_compositor_show_tile_preview (MetaCompositor *compositor,
|
||||
int tile_monitor_number)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (!info->plugin_mgr)
|
||||
return;
|
||||
|
||||
meta_plugin_manager_show_tile_preview (info->plugin_mgr,
|
||||
window, tile_rect, tile_monitor_number);
|
||||
}
|
||||
@@ -1717,21 +1610,5 @@ meta_compositor_hide_tile_preview (MetaCompositor *compositor,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
|
||||
if (!info->plugin_mgr)
|
||||
return;
|
||||
|
||||
meta_plugin_manager_hide_tile_preview (info->plugin_mgr);
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_show_window_menu (MetaCompositor *compositor,
|
||||
MetaWindow *window)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (window->screen);
|
||||
|
||||
if (!info->plugin_mgr)
|
||||
return;
|
||||
|
||||
meta_plugin_manager_show_window_menu (info->plugin_mgr, window);
|
||||
}
|
||||
|
@@ -100,7 +100,9 @@ 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, "screen", screen, NULL);
|
||||
plugin_mgr->plugin = plugin = g_object_new (plugin_type, NULL);
|
||||
|
||||
_meta_plugin_set_screen (plugin, screen);
|
||||
|
||||
klass = META_PLUGIN_GET_CLASS (plugin);
|
||||
|
||||
@@ -165,8 +167,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->minimize (plugin, actor);
|
||||
}
|
||||
break;
|
||||
@@ -176,8 +176,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->map (plugin, actor);
|
||||
}
|
||||
break;
|
||||
@@ -185,7 +183,6 @@ meta_plugin_manager_event_simple (MetaPluginManager *plugin_mgr,
|
||||
if (klass->destroy)
|
||||
{
|
||||
retval = TRUE;
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->destroy (plugin, actor);
|
||||
}
|
||||
break;
|
||||
@@ -230,8 +227,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->maximize (plugin, actor,
|
||||
target_x, target_y,
|
||||
target_width, target_height);
|
||||
@@ -243,8 +238,6 @@ meta_plugin_manager_event_maximize (MetaPluginManager *plugin_mgr,
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_window_effects (plugin_mgr,
|
||||
actor);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->unmaximize (plugin, actor,
|
||||
target_x, target_y,
|
||||
target_width, target_height);
|
||||
@@ -283,8 +276,6 @@ meta_plugin_manager_switch_workspace (MetaPluginManager *plugin_mgr,
|
||||
{
|
||||
retval = TRUE;
|
||||
meta_plugin_manager_kill_switch_workspace (plugin_mgr);
|
||||
|
||||
_meta_plugin_effect_started (plugin);
|
||||
klass->switch_workspace (plugin, from, to, direction);
|
||||
}
|
||||
|
||||
@@ -365,18 +356,3 @@ meta_plugin_manager_hide_tile_preview (MetaPluginManager *plugin_mgr)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_plugin_manager_show_window_menu (MetaPluginManager *plugin_mgr,
|
||||
MetaWindow *window)
|
||||
{
|
||||
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;
|
||||
|
||||
if (klass->show_window_menu)
|
||||
klass->show_window_menu (plugin, window);
|
||||
}
|
||||
|
@@ -80,8 +80,4 @@ gboolean meta_plugin_manager_show_tile_preview (MetaPluginManager *mgr,
|
||||
MetaRectangle *tile_rect,
|
||||
int tile_monitor_number);
|
||||
gboolean meta_plugin_manager_hide_tile_preview (MetaPluginManager *mgr);
|
||||
|
||||
void meta_plugin_manager_show_window_menu (MetaPluginManager *mgr,
|
||||
MetaWindow *window);
|
||||
|
||||
#endif
|
||||
|
@@ -47,91 +47,15 @@ G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
|
||||
#define META_PLUGIN_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate))
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SCREEN,
|
||||
PROP_DEBUG_MODE,
|
||||
};
|
||||
|
||||
struct _MetaPluginPrivate
|
||||
{
|
||||
MetaScreen *screen;
|
||||
|
||||
gint running;
|
||||
gboolean debug : 1;
|
||||
MetaScreen *screen;
|
||||
};
|
||||
|
||||
static void
|
||||
meta_plugin_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCREEN:
|
||||
priv->screen = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_DEBUG_MODE:
|
||||
priv->debug = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_plugin_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCREEN:
|
||||
g_value_set_object (value, priv->screen);
|
||||
break;
|
||||
case PROP_DEBUG_MODE:
|
||||
g_value_set_boolean (value, priv->debug);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
meta_plugin_class_init (MetaPluginClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = meta_plugin_set_property;
|
||||
gobject_class->get_property = meta_plugin_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SCREEN,
|
||||
g_param_spec_object ("screen",
|
||||
"MetaScreen",
|
||||
"MetaScreen",
|
||||
META_TYPE_SCREEN,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DEBUG_MODE,
|
||||
g_param_spec_boolean ("debug-mode",
|
||||
"Debug Mode",
|
||||
"Debug Mode",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate));
|
||||
g_type_class_add_private (klass, sizeof (MetaPluginPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -140,22 +64,6 @@ meta_plugin_init (MetaPlugin *self)
|
||||
self->priv = META_PLUGIN_GET_PRIVATE (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_plugin_running (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return (priv->running > 0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_plugin_debug_mode (MetaPlugin *plugin)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
return priv->debug;
|
||||
}
|
||||
|
||||
const MetaPluginInfo *
|
||||
meta_plugin_get_info (MetaPlugin *plugin)
|
||||
{
|
||||
@@ -167,21 +75,6 @@ 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)
|
||||
@@ -208,15 +101,8 @@ 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);
|
||||
}
|
||||
|
||||
@@ -225,26 +111,6 @@ meta_plugin_window_effect_completed (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor,
|
||||
unsigned long event)
|
||||
{
|
||||
MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
|
||||
|
||||
if (priv->running-- < 0)
|
||||
{
|
||||
g_warning ("Error in running effect accounting, adjusting.");
|
||||
priv->running = 0;
|
||||
}
|
||||
|
||||
if (!actor)
|
||||
{
|
||||
const MetaPluginInfo *info;
|
||||
const gchar *name = NULL;
|
||||
|
||||
if (plugin && (info = meta_plugin_get_info (plugin)))
|
||||
name = info->name;
|
||||
|
||||
g_warning ("Plugin [%s] passed NULL for actor!",
|
||||
name ? name : "unknown");
|
||||
}
|
||||
|
||||
meta_window_actor_effect_completed (actor, event);
|
||||
}
|
||||
|
||||
@@ -339,9 +205,7 @@ meta_plugin_end_modal (MetaPlugin *plugin,
|
||||
* meta_plugin_get_screen:
|
||||
* @plugin: a #MetaPlugin
|
||||
*
|
||||
* Gets the #MetaScreen corresponding to a plugin. Each plugin instance
|
||||
* is associated with exactly one screen; if Metacity is managing
|
||||
* multiple screens, multiple plugin instances will be created.
|
||||
* Gets the #MetaScreen corresponding to a plugin.
|
||||
*
|
||||
* Return value: (transfer none): the #MetaScreen for the plugin
|
||||
*/
|
||||
@@ -353,6 +217,15 @@ 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)
|
||||
|
@@ -28,7 +28,8 @@
|
||||
|
||||
#include <cogl/cogl-wayland-server.h>
|
||||
#include "meta-shaped-texture-private.h"
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
|
||||
struct _MetaSurfaceActorWaylandPrivate
|
||||
{
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "meta-surface-actor.h"
|
||||
|
||||
#include "meta-wayland.h"
|
||||
#include "wayland/meta-wayland.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@@ -20,7 +20,6 @@
|
||||
#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"
|
||||
@@ -30,11 +29,12 @@
|
||||
#include "region-utils.h"
|
||||
#include "monitor-private.h"
|
||||
#include "meta-cullable.h"
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
#include "meta-surface-actor.h"
|
||||
#include "meta-surface-actor-x11.h"
|
||||
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
|
||||
struct _MetaWindowActorPrivate
|
||||
{
|
||||
MetaWindow *window;
|
||||
@@ -968,9 +968,6 @@ 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:
|
||||
@@ -1299,8 +1296,7 @@ meta_window_actor_maximize (MetaWindowActor *self,
|
||||
self->priv->maximize_in_progress++;
|
||||
meta_window_actor_freeze (self);
|
||||
|
||||
if (!info->plugin_mgr ||
|
||||
!meta_plugin_manager_event_maximize (info->plugin_mgr,
|
||||
if (!meta_plugin_manager_event_maximize (info->plugin_mgr,
|
||||
self,
|
||||
META_PLUGIN_MAXIMIZE,
|
||||
new_rect->x, new_rect->y,
|
||||
@@ -1328,8 +1324,7 @@ meta_window_actor_unmaximize (MetaWindowActor *self,
|
||||
self->priv->unmaximize_in_progress++;
|
||||
meta_window_actor_freeze (self);
|
||||
|
||||
if (!info->plugin_mgr ||
|
||||
!meta_plugin_manager_event_maximize (info->plugin_mgr,
|
||||
if (!meta_plugin_manager_event_maximize (info->plugin_mgr,
|
||||
self,
|
||||
META_PLUGIN_UNMAXIMIZE,
|
||||
new_rect->x, new_rect->y,
|
||||
|
@@ -58,88 +58,6 @@
|
||||
#include <canberra-gtk.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* bell_flash_screen:
|
||||
* @display: The display which owns the screen (rather redundant)
|
||||
* @screen: The screen to flash
|
||||
*
|
||||
* Flashes one entire screen. This is done by making a window the size of the
|
||||
* whole screen (or reusing the old one, if it's still around), mapping it,
|
||||
* painting it white and then black, and then unmapping it. We set saveunder so
|
||||
* that all the windows behind it come back immediately.
|
||||
*
|
||||
* Unlike frame flashes, we don't do fullscreen flashes with a timeout; rather,
|
||||
* we do them in one go, because we don't have to rely on the theme code
|
||||
* redrawing the frame for us in order to do the flash.
|
||||
*/
|
||||
/*
|
||||
* Bug: The way I read it, this appears not to do the flash
|
||||
* the first time we flash a particular display. Am I wrong?
|
||||
*
|
||||
* Bug: This appears to destroy our current XSync status.
|
||||
*/
|
||||
static void
|
||||
bell_flash_screen (MetaDisplay *display,
|
||||
MetaScreen *screen)
|
||||
{
|
||||
Window root = screen->xroot;
|
||||
int width = screen->rect.width;
|
||||
int height = screen->rect.height;
|
||||
|
||||
if (screen->flash_window == None)
|
||||
{
|
||||
Visual *visual = (Visual *)CopyFromParent;
|
||||
XSetWindowAttributes xswa;
|
||||
int depth = CopyFromParent;
|
||||
xswa.save_under = True;
|
||||
xswa.override_redirect = True;
|
||||
/*
|
||||
* TODO: use XGetVisualInfo and determine which is an
|
||||
* overlay, if one is present, and use the Overlay visual
|
||||
* for this window (for performance reasons).
|
||||
* Not sure how to tell this yet...
|
||||
*/
|
||||
screen->flash_window = XCreateWindow (display->xdisplay, root,
|
||||
0, 0, width, height,
|
||||
0, depth,
|
||||
InputOutput,
|
||||
visual,
|
||||
/* note: XSun doesn't like SaveUnder here */
|
||||
CWSaveUnder | CWOverrideRedirect,
|
||||
&xswa);
|
||||
XSelectInput (display->xdisplay, screen->flash_window, ExposureMask);
|
||||
XMapWindow (display->xdisplay, screen->flash_window);
|
||||
XSync (display->xdisplay, False);
|
||||
XFlush (display->xdisplay);
|
||||
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just draw something in the window */
|
||||
GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL);
|
||||
XMapWindow (display->xdisplay, screen->flash_window);
|
||||
XSetForeground (display->xdisplay, gc,
|
||||
WhitePixel (display->xdisplay,
|
||||
XScreenNumberOfScreen (screen->xscreen)));
|
||||
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||
0, 0, width, height);
|
||||
XSetForeground (display->xdisplay, gc,
|
||||
BlackPixel (display->xdisplay,
|
||||
XScreenNumberOfScreen (screen->xscreen)));
|
||||
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||
0, 0, width, height);
|
||||
XFlush (display->xdisplay);
|
||||
XSync (display->xdisplay, False);
|
||||
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||
XFreeGC (display->xdisplay, gc);
|
||||
}
|
||||
|
||||
if (meta_prefs_get_focus_mode () != G_DESKTOP_FOCUS_MODE_CLICK &&
|
||||
!display->mouse_mode)
|
||||
meta_display_increment_focus_sentinel (display);
|
||||
XFlush (display->xdisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
* bell_flash_fullscreen:
|
||||
* @display: The display the event came in on
|
||||
@@ -164,12 +82,7 @@ bell_flash_fullscreen (MetaDisplay *display,
|
||||
{
|
||||
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
|
||||
if (screen)
|
||||
{
|
||||
if (display->compositor)
|
||||
meta_compositor_flash_screen (display->compositor, screen);
|
||||
else
|
||||
bell_flash_screen (display, screen);
|
||||
}
|
||||
meta_compositor_flash_screen (display->compositor, screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -177,10 +90,7 @@ bell_flash_fullscreen (MetaDisplay *display,
|
||||
while (screen_list)
|
||||
{
|
||||
screen = (MetaScreen *) screen_list->data;
|
||||
if (display->compositor)
|
||||
meta_compositor_flash_screen (display->compositor, screen);
|
||||
else
|
||||
bell_flash_screen (display, screen);
|
||||
meta_compositor_flash_screen (display->compositor, screen);
|
||||
screen_list = screen_list->next;
|
||||
}
|
||||
}
|
||||
|
@@ -817,7 +817,7 @@ constrain_maximization (MetaWindow *window,
|
||||
active_workspace_struts);
|
||||
}
|
||||
/* Now make target_size = maximized size of client window */
|
||||
/* unextend_by_frame (window, &target_size); */
|
||||
unextend_by_frame (window, &target_size);
|
||||
|
||||
/* Check min size constraints; max size constraints are ignored for maximized
|
||||
* windows, as per bug 327543.
|
||||
|
129
src/core/core.c
129
src/core/core.c
@@ -469,6 +469,9 @@ meta_core_change_workspace (Display *xdisplay,
|
||||
void
|
||||
meta_core_show_window_menu (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWindow *window = get_window (xdisplay, frame_xwindow);
|
||||
@@ -477,7 +480,121 @@ meta_core_show_window_menu (Display *xdisplay,
|
||||
meta_window_raise (window);
|
||||
meta_window_focus (window, timestamp);
|
||||
|
||||
meta_window_show_menu (window);
|
||||
meta_window_show_menu (window, root_x, root_y, button, timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_get_menu_accelerator (MetaMenuOp menu_op,
|
||||
int workspace,
|
||||
unsigned int *keysym,
|
||||
MetaVirtualModifier *modifiers)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = NULL;
|
||||
|
||||
switch (menu_op)
|
||||
{
|
||||
case META_MENU_OP_NONE:
|
||||
/* No keybinding for this one */
|
||||
break;
|
||||
case META_MENU_OP_DELETE:
|
||||
name = "close";
|
||||
break;
|
||||
case META_MENU_OP_MINIMIZE:
|
||||
name = "minimize";
|
||||
break;
|
||||
case META_MENU_OP_UNMAXIMIZE:
|
||||
name = "unmaximize";
|
||||
break;
|
||||
case META_MENU_OP_MAXIMIZE:
|
||||
name = "maximize";
|
||||
break;
|
||||
case META_MENU_OP_UNSHADE:
|
||||
case META_MENU_OP_SHADE:
|
||||
name = "toggle_shaded";
|
||||
break;
|
||||
case META_MENU_OP_UNSTICK:
|
||||
case META_MENU_OP_STICK:
|
||||
name = "toggle-on-all-workspaces";
|
||||
break;
|
||||
case META_MENU_OP_ABOVE:
|
||||
case META_MENU_OP_UNABOVE:
|
||||
name = "toggle-above";
|
||||
break;
|
||||
case META_MENU_OP_WORKSPACES:
|
||||
switch (workspace)
|
||||
{
|
||||
case 1:
|
||||
name = "move-to-workspace-1";
|
||||
break;
|
||||
case 2:
|
||||
name = "move-to-workspace-2";
|
||||
break;
|
||||
case 3:
|
||||
name = "move-to-workspace-3";
|
||||
break;
|
||||
case 4:
|
||||
name = "move-to-workspace-4";
|
||||
break;
|
||||
case 5:
|
||||
name = "move-to-workspace-5";
|
||||
break;
|
||||
case 6:
|
||||
name = "move-to-workspace-6";
|
||||
break;
|
||||
case 7:
|
||||
name = "move-to-workspace-7";
|
||||
break;
|
||||
case 8:
|
||||
name = "move-to-workspace-8";
|
||||
break;
|
||||
case 9:
|
||||
name = "move-to-workspace-9";
|
||||
break;
|
||||
case 10:
|
||||
name = "move-to-workspace-10";
|
||||
break;
|
||||
case 11:
|
||||
name = "move-to-workspace-11";
|
||||
break;
|
||||
case 12:
|
||||
name = "move-to-workspace-12";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case META_MENU_OP_MOVE:
|
||||
name = "begin-move";
|
||||
break;
|
||||
case META_MENU_OP_RESIZE:
|
||||
name = "begin-resize";
|
||||
break;
|
||||
case META_MENU_OP_MOVE_LEFT:
|
||||
name = "move-to-workspace-left";
|
||||
break;
|
||||
case META_MENU_OP_MOVE_RIGHT:
|
||||
name = "move-to-workspace-right";
|
||||
break;
|
||||
case META_MENU_OP_MOVE_UP:
|
||||
name = "move-to-workspace-up";
|
||||
break;
|
||||
case META_MENU_OP_MOVE_DOWN:
|
||||
name = "move-to-workspace-down";
|
||||
break;
|
||||
case META_MENU_OP_RECOVER:
|
||||
/* No keybinding for this one */
|
||||
break;
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
meta_prefs_get_window_binding (name, keysym, modifiers);
|
||||
}
|
||||
else
|
||||
{
|
||||
*keysym = 0;
|
||||
*modifiers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
@@ -601,16 +718,6 @@ meta_core_set_screen_cursor (Display *xdisplay,
|
||||
meta_frame_set_screen_cursor (window->frame, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
meta_core_increment_event_serial (Display *xdisplay)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
|
||||
display = meta_display_for_x_display (xdisplay);
|
||||
|
||||
meta_display_increment_event_serial (display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_invalidate_default_icons (void)
|
||||
{
|
||||
|
@@ -159,8 +159,15 @@ const char* meta_core_get_workspace_name_with_index (Display *xdisplay,
|
||||
|
||||
void meta_core_show_window_menu (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp);
|
||||
|
||||
void meta_core_get_menu_accelerator (MetaMenuOp menu_op,
|
||||
int workspace,
|
||||
unsigned int *keysym,
|
||||
MetaVirtualModifier *modifiers);
|
||||
|
||||
gboolean meta_core_begin_grab_op (Display *xdisplay,
|
||||
Window frame_xwindow,
|
||||
@@ -186,12 +193,6 @@ void meta_core_set_screen_cursor (Display *xdisplay,
|
||||
Window frame_on_screen,
|
||||
MetaCursor cursor);
|
||||
|
||||
/* Used because we ignore EnterNotify when a window is unmapped that
|
||||
* really shouldn't cause focus changes, by comparing the event serial
|
||||
* of the EnterNotify and the UnmapNotify.
|
||||
*/
|
||||
void meta_core_increment_event_serial (Display *display);
|
||||
|
||||
void meta_invalidate_default_icons (void);
|
||||
|
||||
void meta_core_add_old_event_mask (Display *xdisplay,
|
||||
|
@@ -37,7 +37,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "meta-wayland-surface.h"
|
||||
#include "wayland/meta-wayland-surface.h"
|
||||
|
||||
static void meta_window_present_delete_dialog (MetaWindow *window,
|
||||
guint32 timestamp);
|
||||
@@ -261,8 +261,7 @@ meta_window_present_delete_dialog (MetaWindow *window, guint32 timestamp)
|
||||
{
|
||||
MetaWindow *w = tmp->data;
|
||||
|
||||
if (w->xtransient_for == window->xwindow &&
|
||||
w->res_class &&
|
||||
if (w->transient_for == window && w->res_class &&
|
||||
g_ascii_strcasecmp (w->res_class, "mutter-dialog") == 0)
|
||||
{
|
||||
meta_window_activate (w, timestamp);
|
||||
|
@@ -263,6 +263,10 @@ struct _MetaDisplay
|
||||
/* Managed by group.c */
|
||||
GHashTable *groups_by_leader;
|
||||
|
||||
/* currently-active window menu if any */
|
||||
MetaWindowMenu *window_menu;
|
||||
MetaWindow *window_with_menu;
|
||||
|
||||
/* Managed by window-props.c */
|
||||
MetaWindowPropHooks *prop_hooks_table;
|
||||
GHashTable *prop_hooks;
|
||||
|
@@ -36,15 +36,11 @@
|
||||
#include <meta/main.h>
|
||||
#include "screen-private.h"
|
||||
#include "window-private.h"
|
||||
#include "window-x11.h"
|
||||
#include "window-props.h"
|
||||
#include "group-props.h"
|
||||
#include "frame.h"
|
||||
#include <meta/errors.h>
|
||||
#include "keybindings-private.h"
|
||||
#include <meta/prefs.h>
|
||||
#include "resizepopup.h"
|
||||
#include "xprops.h"
|
||||
#include "workspace-private.h"
|
||||
#include "bell.h"
|
||||
#include <meta/compositor.h>
|
||||
@@ -72,7 +68,12 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "meta-xwayland-private.h"
|
||||
#include "x11/window-x11.h"
|
||||
#include "x11/window-props.h"
|
||||
#include "x11/group-props.h"
|
||||
#include "x11/xprops.h"
|
||||
|
||||
#include "wayland/meta-xwayland-private.h"
|
||||
#include "meta-surface-actor-wayland.h"
|
||||
|
||||
/*
|
||||
@@ -175,8 +176,6 @@ static void prefs_changed_callback (MetaPreference pref,
|
||||
|
||||
static void sanity_check_timestamps (MetaDisplay *display,
|
||||
guint32 known_good_timestamp);
|
||||
|
||||
MetaGroup* get_focussed_group (MetaDisplay *display);
|
||||
|
||||
static void
|
||||
meta_display_get_property(GObject *object,
|
||||
@@ -564,6 +563,9 @@ meta_display_open (void)
|
||||
the_display->monitor_cache_invalidated = TRUE;
|
||||
|
||||
the_display->groups_by_leader = NULL;
|
||||
|
||||
the_display->window_with_menu = NULL;
|
||||
the_display->window_menu = NULL;
|
||||
|
||||
the_display->screens = NULL;
|
||||
the_display->active_screen = NULL;
|
||||
@@ -2203,7 +2205,11 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
{
|
||||
if (meta_prefs_get_raise_on_click ())
|
||||
meta_window_raise (window);
|
||||
meta_window_show_menu (window);
|
||||
meta_window_show_menu (window,
|
||||
event->button.x,
|
||||
event->button.y,
|
||||
event->button.button,
|
||||
event->any.time);
|
||||
bypass_clutter = TRUE;
|
||||
bypass_wayland = TRUE;
|
||||
}
|
||||
@@ -2614,7 +2620,7 @@ handle_other_xevent (MetaDisplay *display,
|
||||
/* NB: override redirect windows wont cause a map request so we
|
||||
* watch out for map notifies against any root windows too if a
|
||||
* compositor is enabled: */
|
||||
if (display->compositor && window == NULL
|
||||
if (window == NULL
|
||||
&& meta_display_screen_for_root (display, event->xmap.event))
|
||||
{
|
||||
window = meta_window_x11_new (display, event->xmap.window,
|
||||
@@ -2669,7 +2675,7 @@ handle_other_xevent (MetaDisplay *display,
|
||||
}
|
||||
|
||||
if (window && window->override_redirect)
|
||||
meta_window_configure_notify (window, &event->xconfigure);
|
||||
meta_window_x11_configure_notify (window, &event->xconfigure);
|
||||
|
||||
break;
|
||||
case ConfigureRequest:
|
||||
@@ -3078,7 +3084,7 @@ meta_display_handle_xevent (MetaDisplay *display,
|
||||
}
|
||||
|
||||
out:
|
||||
if (display->compositor && !bypass_compositor)
|
||||
if (!bypass_compositor)
|
||||
{
|
||||
MetaWindow *window = modified != None ? meta_display_lookup_x_window (display, modified) : NULL;
|
||||
|
||||
@@ -4769,8 +4775,8 @@ meta_display_pong_for_serial (MetaDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
MetaGroup*
|
||||
get_focussed_group (MetaDisplay *display)
|
||||
static MetaGroup *
|
||||
get_focused_group (MetaDisplay *display)
|
||||
{
|
||||
if (display->focus_window)
|
||||
return display->focus_window->group;
|
||||
@@ -4780,7 +4786,7 @@ get_focussed_group (MetaDisplay *display)
|
||||
|
||||
#define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \
|
||||
|| ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \
|
||||
|| ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))) \
|
||||
|| ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focused_group (w->display))) \
|
||||
|| ((t) == META_TAB_LIST_NORMAL_ALL && META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w)))
|
||||
|
||||
static MetaWindow*
|
||||
|
@@ -41,7 +41,6 @@
|
||||
#include "screen-private.h"
|
||||
#include <meta/prefs.h>
|
||||
#include "util-private.h"
|
||||
#include "meta-wayland.h"
|
||||
|
||||
#include <X11/keysym.h>
|
||||
#include <string.h>
|
||||
@@ -52,6 +51,8 @@
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
|
||||
#include "wayland/meta-wayland.h"
|
||||
|
||||
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
|
||||
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
|
||||
#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings"
|
||||
@@ -2782,7 +2783,20 @@ handle_activate_window_menu (MetaDisplay *display,
|
||||
gpointer dummy)
|
||||
{
|
||||
if (display->focus_window)
|
||||
meta_window_show_menu (display->focus_window);
|
||||
{
|
||||
int x, y;
|
||||
|
||||
meta_window_get_position (display->focus_window,
|
||||
&x, &y);
|
||||
|
||||
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
|
||||
x += display->focus_window->rect.width;
|
||||
|
||||
meta_window_show_menu (display->focus_window,
|
||||
x, y,
|
||||
0,
|
||||
event->time);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -50,10 +50,8 @@
|
||||
#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.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib-unix.h>
|
||||
@@ -79,6 +77,10 @@
|
||||
#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.
|
||||
*/
|
||||
|
@@ -47,9 +47,10 @@
|
||||
|
||||
#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
|
||||
|
||||
|
@@ -344,7 +344,7 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
|
||||
/* denied_focus_and_not_transient is only set when focus_window != NULL */
|
||||
|
||||
if (window->denied_focus_and_not_transient &&
|
||||
window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
|
||||
window->type == META_WINDOW_MODAL_DIALOG &&
|
||||
meta_window_same_application (window, focus_window) &&
|
||||
window_overlaps_focus_window (window))
|
||||
{
|
||||
@@ -610,7 +610,7 @@ meta_window_place (MetaWindow *window,
|
||||
meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc);
|
||||
|
||||
windows = NULL;
|
||||
|
||||
|
||||
switch (window->type)
|
||||
{
|
||||
/* Run placement algorithm on these. */
|
||||
@@ -638,7 +638,7 @@ meta_window_place (MetaWindow *window,
|
||||
case META_WINDOW_OVERRIDE_OTHER:
|
||||
goto done_no_constraints;
|
||||
}
|
||||
|
||||
|
||||
if (meta_prefs_get_disable_workarounds ())
|
||||
{
|
||||
switch (window->type)
|
||||
@@ -699,18 +699,11 @@ meta_window_place (MetaWindow *window,
|
||||
goto done_no_constraints;
|
||||
}
|
||||
}
|
||||
|
||||
if ((window->type == META_WINDOW_DIALOG ||
|
||||
window->type == META_WINDOW_MODAL_DIALOG) &&
|
||||
window->xtransient_for != None)
|
||||
{
|
||||
/* Center horizontally, at top of parent vertically */
|
||||
|
||||
MetaWindow *parent;
|
||||
|
||||
parent =
|
||||
meta_display_lookup_x_window (window->display,
|
||||
window->xtransient_for);
|
||||
if (window->type == META_WINDOW_DIALOG ||
|
||||
window->type == META_WINDOW_MODAL_DIALOG)
|
||||
{
|
||||
MetaWindow *parent = meta_window_get_transient_for (window);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
|
@@ -2241,6 +2241,43 @@ meta_prefs_get_keybinding_action (const char *name)
|
||||
: META_KEYBINDING_ACTION_NONE;
|
||||
}
|
||||
|
||||
/* This is used by the menu system to decide what key binding
|
||||
* to display next to an option. We return the first non-disabled
|
||||
* binding, if any.
|
||||
*/
|
||||
void
|
||||
meta_prefs_get_window_binding (const char *name,
|
||||
unsigned int *keysym,
|
||||
MetaVirtualModifier *modifiers)
|
||||
{
|
||||
MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
|
||||
|
||||
if (pref->per_window)
|
||||
{
|
||||
GSList *s = pref->combos;
|
||||
|
||||
while (s)
|
||||
{
|
||||
MetaKeyCombo *c = s->data;
|
||||
|
||||
if (c->keysym != 0 || c->modifiers != 0)
|
||||
{
|
||||
*keysym = c->keysym;
|
||||
*modifiers = c->modifiers;
|
||||
return;
|
||||
}
|
||||
|
||||
s = s->next;
|
||||
}
|
||||
|
||||
/* Not found; return the disabled value */
|
||||
*keysym = *modifiers = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gint
|
||||
meta_prefs_get_mouse_button_resize (void)
|
||||
{
|
||||
|
@@ -39,11 +39,9 @@
|
||||
#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.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
@@ -54,6 +52,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "x11/xprops.h"
|
||||
|
||||
static char* get_screen_name (MetaDisplay *display,
|
||||
int number);
|
||||
|
||||
@@ -310,7 +310,6 @@ set_supported_hint (MetaScreen *screen)
|
||||
#undef EWMH_ATOMS_ONLY
|
||||
|
||||
screen->display->atom__GTK_FRAME_EXTENTS,
|
||||
screen->display->atom__GTK_SHOW_WINDOW_MENU,
|
||||
};
|
||||
|
||||
XChangeProperty (screen->display->xdisplay, screen->xroot,
|
||||
@@ -810,11 +809,8 @@ meta_screen_free (MetaScreen *screen,
|
||||
|
||||
meta_display_grab (display);
|
||||
|
||||
if (screen->display->compositor)
|
||||
{
|
||||
meta_compositor_unmanage_screen (screen->display->compositor,
|
||||
screen);
|
||||
}
|
||||
meta_compositor_unmanage_screen (screen->display->compositor,
|
||||
screen);
|
||||
|
||||
meta_display_unmanage_windows_for_screen (display, screen, timestamp);
|
||||
|
||||
@@ -2524,10 +2520,9 @@ on_monitors_changed (MetaMonitorManager *manager,
|
||||
&changes);
|
||||
}
|
||||
|
||||
if (screen->display->compositor)
|
||||
meta_compositor_sync_screen_size (screen->display->compositor,
|
||||
screen,
|
||||
screen->rect.width, screen->rect.height);
|
||||
meta_compositor_sync_screen_size (screen->display->compositor,
|
||||
screen,
|
||||
screen->rect.width, screen->rect.height);
|
||||
|
||||
/* Queue a resize on all the windows */
|
||||
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
|
||||
|
@@ -1245,10 +1245,9 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
|
||||
meta_windows = g_list_prepend (meta_windows, window->wayland.meta_window);
|
||||
}
|
||||
|
||||
if (tracker->screen->display->compositor)
|
||||
meta_compositor_sync_stack (tracker->screen->display->compositor,
|
||||
tracker->screen,
|
||||
meta_windows);
|
||||
meta_compositor_sync_stack (tracker->screen->display->compositor,
|
||||
tracker->screen,
|
||||
meta_windows);
|
||||
g_list_free (meta_windows);
|
||||
|
||||
meta_screen_restacked (tracker->screen);
|
||||
|
@@ -36,6 +36,8 @@
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "x11/group-private.h"
|
||||
|
||||
#define WINDOW_HAS_TRANSIENT_TYPE(w) \
|
||||
(w->type == META_WINDOW_DIALOG || \
|
||||
w->type == META_WINDOW_MODAL_DIALOG || \
|
||||
@@ -1705,8 +1707,8 @@ get_default_focus_window (MetaStack *stack,
|
||||
MetaWindow *topmost_in_group;
|
||||
MetaWindow *topmost_overall;
|
||||
MetaGroup *not_this_one_group;
|
||||
GList *link;
|
||||
|
||||
GList *l;
|
||||
|
||||
transient_parent = NULL;
|
||||
topmost_in_group = NULL;
|
||||
topmost_overall = NULL;
|
||||
@@ -1718,49 +1720,49 @@ get_default_focus_window (MetaStack *stack,
|
||||
stack_ensure_sorted (stack);
|
||||
|
||||
/* top of this layer is at the front of the list */
|
||||
link = stack->sorted;
|
||||
|
||||
while (link)
|
||||
for (l = stack->sorted; l != NULL; l = l->next)
|
||||
{
|
||||
MetaWindow *window = link->data;
|
||||
MetaWindow *window = l->data;
|
||||
|
||||
if (window &&
|
||||
window != not_this_one &&
|
||||
(window->unmaps_pending == 0) &&
|
||||
!window->minimized &&
|
||||
(window->input || window->take_focus) &&
|
||||
(workspace == NULL ||
|
||||
meta_window_located_on_workspace (window, workspace)))
|
||||
if (!window)
|
||||
continue;
|
||||
|
||||
if (window == not_this_one)
|
||||
continue;
|
||||
|
||||
if (window->unmaps_pending > 0)
|
||||
continue;
|
||||
|
||||
if (window->minimized)
|
||||
continue;
|
||||
|
||||
if (!(window->input || window->take_focus))
|
||||
continue;
|
||||
|
||||
if (workspace != NULL && !meta_window_located_on_workspace (window, workspace))
|
||||
continue;
|
||||
|
||||
if (must_be_at_point && !window_contains_point (window, root_x, root_y))
|
||||
continue;
|
||||
|
||||
if (not_this_one != NULL)
|
||||
{
|
||||
if (not_this_one != NULL)
|
||||
{
|
||||
if (transient_parent == NULL &&
|
||||
not_this_one->xtransient_for != None &&
|
||||
not_this_one->xtransient_for == window->xwindow &&
|
||||
(!must_be_at_point ||
|
||||
window_contains_point (window, root_x, root_y)))
|
||||
transient_parent = window;
|
||||
if (transient_parent == NULL &&
|
||||
meta_window_get_transient_for (not_this_one) == window)
|
||||
transient_parent = window;
|
||||
|
||||
if (topmost_in_group == NULL &&
|
||||
not_this_one_group != NULL &&
|
||||
not_this_one_group == meta_window_get_group (window) &&
|
||||
(!must_be_at_point ||
|
||||
window_contains_point (window, root_x, root_y)))
|
||||
topmost_in_group = window;
|
||||
}
|
||||
|
||||
if (topmost_overall == NULL &&
|
||||
window->type != META_WINDOW_DOCK &&
|
||||
(!must_be_at_point ||
|
||||
window_contains_point (window, root_x, root_y)))
|
||||
topmost_overall = window;
|
||||
|
||||
/* We could try to bail out early here for efficiency in
|
||||
* some cases, but it's just not worth the code.
|
||||
*/
|
||||
if (topmost_in_group == NULL &&
|
||||
not_this_one_group != NULL &&
|
||||
not_this_one_group == meta_window_get_group (window))
|
||||
topmost_in_group = window;
|
||||
}
|
||||
|
||||
link = link->next;
|
||||
if (topmost_overall == NULL && window->type != META_WINDOW_DOCK)
|
||||
topmost_overall = window;
|
||||
|
||||
/* We could try to bail out early here for efficiency in
|
||||
* some cases, but it's just not worth the code.
|
||||
*/
|
||||
}
|
||||
|
||||
if (transient_parent)
|
||||
|
@@ -38,12 +38,15 @@
|
||||
#include "screen-private.h"
|
||||
#include <meta/util.h>
|
||||
#include "stack.h"
|
||||
#include "iconcache.h"
|
||||
#include <X11/Xutil.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include "meta-wayland-types.h"
|
||||
|
||||
#include "x11/iconcache.h"
|
||||
#include "x11/group-private.h"
|
||||
|
||||
#include "wayland/meta-wayland-types.h"
|
||||
|
||||
typedef struct _MetaWindowQueue MetaWindowQueue;
|
||||
|
||||
@@ -89,15 +92,13 @@ struct _MetaWindow
|
||||
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
|
||||
@@ -159,8 +160,8 @@ struct _MetaWindow
|
||||
/* Whether we're fullscreen */
|
||||
guint fullscreen : 1;
|
||||
|
||||
/* Whether the urgent flag of WM_HINTS is set */
|
||||
guint wm_hints_urgent : 1;
|
||||
/* Whether the window is marked as urgent */
|
||||
guint urgent : 1;
|
||||
|
||||
/* Whether we have to fullscreen after placement */
|
||||
guint fullscreen_after_placement : 1;
|
||||
@@ -262,13 +263,6 @@ struct _MetaWindow
|
||||
guint has_move_func : 1;
|
||||
guint has_resize_func : 1;
|
||||
guint has_fullscreen_func : 1;
|
||||
|
||||
/* Weird "_NET_WM_STATE_MODAL" flag */
|
||||
guint wm_state_modal : 1;
|
||||
|
||||
/* TRUE if the client forced these on */
|
||||
guint wm_state_skip_taskbar : 1;
|
||||
guint wm_state_skip_pager : 1;
|
||||
|
||||
/* Computed whether to skip taskbar or not */
|
||||
guint skip_taskbar : 1;
|
||||
@@ -322,15 +316,6 @@ struct _MetaWindow
|
||||
|
||||
/* Transient parent is a root window */
|
||||
guint transient_parent_is_root_window : 1;
|
||||
|
||||
/* Info on which props we got our attributes from */
|
||||
guint using_net_wm_name : 1; /* vs. plain wm_name */
|
||||
guint using_net_wm_visible_name : 1; /* tracked so we can clear it */
|
||||
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
|
||||
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
|
||||
|
||||
/* icon props have changed */
|
||||
guint need_reread_icon : 1;
|
||||
|
||||
/* if TRUE, window was maximized at start of current grab op */
|
||||
guint shaken_loose : 1;
|
||||
@@ -431,8 +416,6 @@ struct _MetaWindow
|
||||
* gives the position and size of the client window (i.e. ignoring
|
||||
* the frame).
|
||||
*
|
||||
* Position valid if user_has_moved, size valid if user_has_resized
|
||||
*
|
||||
* Position always in root coords, unlike window->rect.
|
||||
*/
|
||||
MetaRectangle user_rect;
|
||||
@@ -471,10 +454,9 @@ struct _MetaWindowClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*workspace_changed) (MetaWindow *window, int old_workspace);
|
||||
void (*focus) (MetaWindow *window);
|
||||
void (*raised) (MetaWindow *window);
|
||||
void (*unmanaged) (MetaWindow *window);
|
||||
void (*get_default_skip_hints) (MetaWindow *window,
|
||||
gboolean *skip_taskbar_out,
|
||||
gboolean *skip_pager_out);
|
||||
};
|
||||
|
||||
/* These differ from window->has_foo_func in that they consider
|
||||
@@ -567,9 +549,6 @@ void meta_window_change_workspace (MetaWindow *window,
|
||||
/* Return whether the window should be currently mapped */
|
||||
gboolean meta_window_should_be_showing (MetaWindow *window);
|
||||
|
||||
/* See warning in window.c about this function */
|
||||
gboolean __window_is_terminal (MetaWindow *window);
|
||||
|
||||
void meta_window_update_struts (MetaWindow *window);
|
||||
|
||||
/* this gets root coords */
|
||||
@@ -628,13 +607,11 @@ void meta_window_set_current_workspace_hint (MetaWindow *window);
|
||||
|
||||
unsigned long meta_window_get_net_wm_desktop (MetaWindow *window);
|
||||
|
||||
void meta_window_show_menu (MetaWindow *window);
|
||||
|
||||
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);
|
||||
void meta_window_show_menu (MetaWindow *window,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp);
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
void meta_window_update_sync_request_counter (MetaWindow *window,
|
||||
@@ -748,4 +725,9 @@ void meta_window_activate_full (MetaWindow *window,
|
||||
|
||||
gboolean meta_window_is_client_decorated (MetaWindow *window);
|
||||
|
||||
void meta_window_update_monitor (MetaWindow *window);
|
||||
|
||||
void meta_window_set_urgent (MetaWindow *window,
|
||||
gboolean urgent);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,6 @@ item(_GTK_WINDOW_OBJECT_PATH)
|
||||
item(_GTK_APP_MENU_OBJECT_PATH)
|
||||
item(_GTK_MENUBAR_OBJECT_PATH)
|
||||
item(_GTK_FRAME_EXTENTS)
|
||||
item(_GTK_SHOW_WINDOW_MENU)
|
||||
item(_GNOME_WM_KEYBINDINGS)
|
||||
item(_GNOME_PANEL_ACTION)
|
||||
item(_GNOME_PANEL_ACTION_MAIN_MENU)
|
||||
@@ -92,7 +91,6 @@ 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
|
||||
@@ -133,7 +131,6 @@ 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)
|
||||
|
@@ -86,6 +86,61 @@ typedef enum
|
||||
META_FRAME_TILED_RIGHT = 1 << 16
|
||||
} MetaFrameFlags;
|
||||
|
||||
/**
|
||||
* MetaMenuOp:
|
||||
* @META_MENU_OP_NONE: No menu operation
|
||||
* @META_MENU_OP_DELETE: Menu operation delete
|
||||
* @META_MENU_OP_MINIMIZE: Menu operation minimize
|
||||
* @META_MENU_OP_UNMAXIMIZE: Menu operation unmaximize
|
||||
* @META_MENU_OP_MAXIMIZE: Menu operation maximize
|
||||
* @META_MENU_OP_UNSHADE: Menu operation unshade
|
||||
* @META_MENU_OP_SHADE: Menu operation shade
|
||||
* @META_MENU_OP_UNSTICK: Menu operation unstick
|
||||
* @META_MENU_OP_STICK: Menu operation stick
|
||||
* @META_MENU_OP_WORKSPACES: Menu operation workspaces
|
||||
* @META_MENU_OP_MOVE: Menu operation move
|
||||
* @META_MENU_OP_RESIZE: Menu operation resize
|
||||
* @META_MENU_OP_ABOVE: Menu operation above
|
||||
* @META_MENU_OP_UNABOVE: Menu operation unabove
|
||||
* @META_MENU_OP_MOVE_LEFT: Menu operation left
|
||||
* @META_MENU_OP_MOVE_RIGHT: Menu operation right
|
||||
* @META_MENU_OP_MOVE_UP: Menu operation up
|
||||
* @META_MENU_OP_MOVE_DOWN: Menu operation down
|
||||
* @META_MENU_OP_RECOVER: Menu operation recover
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
META_MENU_OP_NONE = 0,
|
||||
META_MENU_OP_DELETE = 1 << 0,
|
||||
META_MENU_OP_MINIMIZE = 1 << 1,
|
||||
META_MENU_OP_UNMAXIMIZE = 1 << 2,
|
||||
META_MENU_OP_MAXIMIZE = 1 << 3,
|
||||
META_MENU_OP_UNSHADE = 1 << 4,
|
||||
META_MENU_OP_SHADE = 1 << 5,
|
||||
META_MENU_OP_UNSTICK = 1 << 6,
|
||||
META_MENU_OP_STICK = 1 << 7,
|
||||
META_MENU_OP_WORKSPACES = 1 << 8,
|
||||
META_MENU_OP_MOVE = 1 << 9,
|
||||
META_MENU_OP_RESIZE = 1 << 10,
|
||||
META_MENU_OP_ABOVE = 1 << 11,
|
||||
META_MENU_OP_UNABOVE = 1 << 12,
|
||||
META_MENU_OP_MOVE_LEFT = 1 << 13,
|
||||
META_MENU_OP_MOVE_RIGHT = 1 << 14,
|
||||
META_MENU_OP_MOVE_UP = 1 << 15,
|
||||
META_MENU_OP_MOVE_DOWN = 1 << 16,
|
||||
META_MENU_OP_RECOVER = 1 << 17
|
||||
} MetaMenuOp;
|
||||
|
||||
typedef struct _MetaWindowMenu MetaWindowMenu;
|
||||
|
||||
typedef void (* MetaWindowMenuFunc) (MetaWindowMenu *menu,
|
||||
Display *xdisplay,
|
||||
Window client_xwindow,
|
||||
guint32 timestamp,
|
||||
MetaMenuOp op,
|
||||
int workspace,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* MetaGrabOp:
|
||||
* @META_GRAB_OP_NONE: None
|
||||
@@ -108,13 +163,6 @@ typedef enum
|
||||
* @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
|
||||
|
@@ -130,7 +130,5 @@ void meta_compositor_show_tile_preview (MetaCompositor *compositor,
|
||||
int tile_monitor_number);
|
||||
void meta_compositor_hide_tile_preview (MetaCompositor *compositor,
|
||||
MetaScreen *screen);
|
||||
void meta_compositor_show_window_menu (MetaCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
#endif /* META_COMPOSITOR_H */
|
||||
|
@@ -164,9 +164,6 @@ struct _MetaPluginClass
|
||||
int tile_monitor_number);
|
||||
void (*hide_tile_preview) (MetaPlugin *plugin);
|
||||
|
||||
void (*show_window_menu) (MetaPlugin *plugin,
|
||||
MetaWindow *window);
|
||||
|
||||
/**
|
||||
* MetaPluginClass::kill_window_effects:
|
||||
* @actor: a #MetaWindowActor
|
||||
@@ -257,9 +254,6 @@ 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);
|
||||
|
||||
/**
|
||||
@@ -411,8 +405,7 @@ meta_plugin_end_modal (MetaPlugin *plugin,
|
||||
|
||||
MetaScreen *meta_plugin_get_screen (MetaPlugin *plugin);
|
||||
|
||||
void
|
||||
_meta_plugin_effect_started (MetaPlugin *plugin);
|
||||
void _meta_plugin_set_screen (MetaPlugin *plugin, MetaScreen *screen);
|
||||
|
||||
/* XXX: Putting this in here so it's in the public header. */
|
||||
void meta_plugin_manager_set_plugin_type (GType gtype);
|
||||
|
@@ -392,6 +392,10 @@ GType meta_key_binding_get_type (void);
|
||||
|
||||
MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
|
||||
|
||||
void meta_prefs_get_window_binding (const char *name,
|
||||
unsigned int *keysym,
|
||||
MetaVirtualModifier *modifiers);
|
||||
|
||||
gboolean meta_prefs_get_visual_bell (void);
|
||||
gboolean meta_prefs_bell_is_audible (void);
|
||||
GDesktopVisualBellType meta_prefs_get_visual_bell_type (void);
|
||||
|
@@ -125,7 +125,6 @@ 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);
|
||||
@@ -165,7 +164,6 @@ 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);
|
||||
@@ -205,7 +203,6 @@ 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);
|
||||
@@ -213,7 +210,6 @@ 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);
|
||||
|
||||
@@ -263,4 +259,7 @@ 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
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
_Name=Mutter (wayland compositor)
|
||||
Exec=mutter --wayland --display-server
|
||||
Exec=mutter-launch -- mutter --wayland --display-server
|
||||
NoDisplay=true
|
||||
# name of loadable control center module
|
||||
X-GNOME-WMSettingsModule=metacity
|
||||
|
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.login1.Session">
|
||||
<property name="Active" type="b" access="read" />
|
||||
|
||||
<method name="Activate">
|
||||
</method>
|
||||
<method name="TakeControl">
|
||||
<arg name="force" type="b"/>
|
||||
</method>
|
||||
<method name="TakeDevice">
|
||||
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
|
||||
<arg name="major" type="u" direction="in"/>
|
||||
<arg name="minor" type="u" direction="in"/>
|
||||
<arg name="fd" type="h" direction="out"/>
|
||||
<arg name="paused" type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="ReleaseDevice">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
</method>
|
||||
<method name="PauseDeviceComplete">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
</method>
|
||||
<signal name="PauseDevice">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
<arg name="type" type="s"/>
|
||||
</signal>
|
||||
<signal name="ResumeDevice">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
<arg name="fd" type="h"/>
|
||||
</signal>
|
||||
</interface>
|
||||
|
||||
<interface name="org.freedesktop.login1.Seat">
|
||||
<method name="SwitchTo">
|
||||
<arg name="vt" type="u"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
@@ -1,109 +0,0 @@
|
||||
#! /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
|
@@ -1106,6 +1106,9 @@ meta_frame_titlebar_event (MetaUIFrame *frame,
|
||||
case G_DESKTOP_TITLEBAR_ACTION_MENU:
|
||||
meta_core_show_window_menu (display,
|
||||
frame->xwindow,
|
||||
event->x_root,
|
||||
event->y_root,
|
||||
event->button,
|
||||
event->time);
|
||||
break;
|
||||
}
|
||||
@@ -1265,9 +1268,30 @@ meta_frames_button_press_event (GtkWidget *widget,
|
||||
redraw_control (frames, frame, control);
|
||||
|
||||
if (op == META_GRAB_OP_CLICKING_MENU)
|
||||
meta_core_show_window_menu (display,
|
||||
frame->xwindow,
|
||||
event->time);
|
||||
{
|
||||
MetaFrameGeometry fgeom;
|
||||
GdkRectangle *rect;
|
||||
int dx, dy;
|
||||
|
||||
meta_frames_calc_geometry (frames, frame, &fgeom);
|
||||
|
||||
rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
|
||||
|
||||
/* get delta to convert to root coords */
|
||||
dx = event->x_root - event->x;
|
||||
dy = event->y_root - event->y;
|
||||
|
||||
/* Align to the right end of the menu rectangle if RTL */
|
||||
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
|
||||
dx += rect->width;
|
||||
|
||||
meta_core_show_window_menu (display,
|
||||
frame->xwindow,
|
||||
rect->x + dx,
|
||||
rect->y + rect->height + dy,
|
||||
event->button,
|
||||
event->time);
|
||||
}
|
||||
}
|
||||
else if (event->button == 1 &&
|
||||
(control == META_FRAME_CONTROL_RESIZE_SE ||
|
||||
|
518
src/ui/menu.c
Normal file
518
src/ui/menu.c
Normal file
@@ -0,0 +1,518 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/* Mutter window menu */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2004 Rob Adams
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "menu.h"
|
||||
#include <meta/main.h>
|
||||
#include "util-private.h"
|
||||
#include "core.h"
|
||||
#include "metaaccellabel.h"
|
||||
#include "ui.h"
|
||||
|
||||
typedef struct _MenuItem MenuItem;
|
||||
typedef struct _MenuData MenuData;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MENU_ITEM_SEPARATOR = 0,
|
||||
MENU_ITEM_NORMAL,
|
||||
MENU_ITEM_CHECKBOX,
|
||||
MENU_ITEM_RADIOBUTTON,
|
||||
MENU_ITEM_WORKSPACE_LIST,
|
||||
} MetaMenuItemType;
|
||||
|
||||
struct _MenuItem
|
||||
{
|
||||
MetaMenuOp op;
|
||||
MetaMenuItemType type;
|
||||
const gboolean checked;
|
||||
const char *label;
|
||||
};
|
||||
|
||||
|
||||
struct _MenuData
|
||||
{
|
||||
MetaWindowMenu *menu;
|
||||
MetaMenuOp op;
|
||||
};
|
||||
|
||||
static void activate_cb (GtkWidget *menuitem, gpointer data);
|
||||
|
||||
static MenuItem menuitems[] = {
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MINIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Mi_nimize") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Ma_ximize") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_UNMAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Unma_ximize") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_SHADE, MENU_ITEM_NORMAL, FALSE, N_("Roll _Up") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_UNSHADE, MENU_ITEM_NORMAL, FALSE, N_("_Unroll") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MOVE, MENU_ITEM_NORMAL, FALSE, N_("_Move") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_RESIZE, MENU_ITEM_NORMAL, FALSE, N_("_Resize") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_RECOVER, MENU_ITEM_NORMAL, FALSE, N_("Move Titlebar On_screen") },
|
||||
{ META_MENU_OP_WORKSPACES, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_ABOVE, MENU_ITEM_CHECKBOX, FALSE, N_("Always on _Top") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_UNABOVE, MENU_ITEM_CHECKBOX, TRUE, N_("Always on _Top") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_STICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Always on Visible Workspace") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_UNSTICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Only on This Workspace") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MOVE_LEFT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Left") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MOVE_RIGHT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace R_ight") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MOVE_UP, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Up") },
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_MOVE_DOWN, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Down") },
|
||||
{ 0, MENU_ITEM_WORKSPACE_LIST, FALSE, NULL },
|
||||
{ 0, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */
|
||||
/* Translators: Translate this string the same way as you do in libwnck! */
|
||||
{ META_MENU_OP_DELETE, MENU_ITEM_NORMAL, FALSE, N_("_Close") }
|
||||
};
|
||||
|
||||
static void
|
||||
popup_position_func (GtkMenu *menu,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gboolean *push_in,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkRequisition req;
|
||||
GdkPoint *pos;
|
||||
|
||||
pos = user_data;
|
||||
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
|
||||
|
||||
*x = pos->x;
|
||||
*y = pos->y;
|
||||
|
||||
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
|
||||
*x = MAX (0, *x - req.width);
|
||||
|
||||
/* Ensure onscreen */
|
||||
*x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
|
||||
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
|
||||
}
|
||||
|
||||
static void
|
||||
menu_closed (GtkMenu *widget,
|
||||
gpointer data)
|
||||
{
|
||||
MetaWindowMenu *menu;
|
||||
|
||||
menu = data;
|
||||
|
||||
meta_frames_notify_menu_hide (menu->frames);
|
||||
(* menu->func) (menu,
|
||||
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
|
||||
menu->client_xwindow,
|
||||
gtk_get_current_event_time (),
|
||||
0, 0,
|
||||
menu->data);
|
||||
|
||||
/* menu may now be freed */
|
||||
}
|
||||
|
||||
static void
|
||||
activate_cb (GtkWidget *menuitem, gpointer data)
|
||||
{
|
||||
MenuData *md;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (menuitem));
|
||||
|
||||
md = data;
|
||||
|
||||
meta_frames_notify_menu_hide (md->menu->frames);
|
||||
(* md->menu->func) (md->menu,
|
||||
GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
|
||||
md->menu->client_xwindow,
|
||||
gtk_get_current_event_time (),
|
||||
md->op,
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem),
|
||||
"workspace")),
|
||||
md->menu->data);
|
||||
|
||||
/* menu may now be freed */
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a Display and an index, get the workspace name and add any
|
||||
* accelerators. At the moment this means adding a _ if the name is of
|
||||
* the form "Workspace n" where n is less than 10, and escaping any
|
||||
* other '_'s so they do not create inadvertant accelerators.
|
||||
*
|
||||
* The calling code owns the string, and is reponsible to free the
|
||||
* memory after use.
|
||||
*
|
||||
* See also http://mail.gnome.org/archives/gnome-i18n/2008-March/msg00380.html
|
||||
* which discusses possible i18n concerns.
|
||||
*/
|
||||
static char*
|
||||
get_workspace_name_with_accel (Display *display,
|
||||
Window xroot,
|
||||
int index)
|
||||
{
|
||||
const char *name;
|
||||
int number;
|
||||
int charcount=0;
|
||||
|
||||
name = meta_core_get_workspace_name_with_index (display, xroot, index);
|
||||
|
||||
g_assert (name != NULL);
|
||||
|
||||
/*
|
||||
* If the name is of the form "Workspace x" where x is an unsigned
|
||||
* integer, insert a '_' before the number if it is less than 10 and
|
||||
* return it
|
||||
*/
|
||||
number = 0;
|
||||
if (sscanf (name, _("Workspace %d%n"), &number, &charcount) != 0 &&
|
||||
*(name + charcount)=='\0')
|
||||
{
|
||||
char *new_name;
|
||||
|
||||
/*
|
||||
* Above name is a pointer into the Workspace struct. Here we make
|
||||
* a copy copy so we can have our wicked way with it.
|
||||
*/
|
||||
if (number == 10)
|
||||
new_name = g_strdup_printf (_("Workspace 1_0"));
|
||||
else
|
||||
new_name = g_strdup_printf (_("Workspace %s%d"),
|
||||
number < 10 ? "_" : "",
|
||||
number);
|
||||
return new_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Otherwise this is just a normal name. Escape any _ characters so that
|
||||
* the user's workspace names do not get mangled. If the number is less
|
||||
* than 10 we provide an accelerator.
|
||||
*/
|
||||
char *new_name;
|
||||
const char *source;
|
||||
char *dest;
|
||||
|
||||
/*
|
||||
* Assume the worst case, that every character is a _. We also
|
||||
* provide memory for " (_#)"
|
||||
*/
|
||||
new_name = g_malloc0 (strlen (name) * 2 + 6 + 1);
|
||||
|
||||
/*
|
||||
* Now iterate down the strings, adding '_' to escape as we go
|
||||
*/
|
||||
dest = new_name;
|
||||
source = name;
|
||||
while (*source != '\0')
|
||||
{
|
||||
if (*source == '_')
|
||||
*dest++ = '_';
|
||||
*dest++ = *source++;
|
||||
}
|
||||
|
||||
/* People don't start at workspace 0, but workspace 1 */
|
||||
if (index < 9)
|
||||
{
|
||||
g_snprintf (dest, 6, " (_%d)", index + 1);
|
||||
}
|
||||
else if (index == 9)
|
||||
{
|
||||
g_snprintf (dest, 6, " (_0)");
|
||||
}
|
||||
|
||||
return new_name;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
menu_item_new (MenuItem *menuitem, int workspace_id)
|
||||
{
|
||||
unsigned int key;
|
||||
MetaVirtualModifier mods;
|
||||
const char *i18n_label;
|
||||
GtkWidget *mi;
|
||||
GtkWidget *accel_label;
|
||||
|
||||
if (menuitem->type == MENU_ITEM_NORMAL)
|
||||
{
|
||||
mi = gtk_menu_item_new ();
|
||||
}
|
||||
else if (menuitem->type == MENU_ITEM_CHECKBOX)
|
||||
{
|
||||
mi = gtk_check_menu_item_new ();
|
||||
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
|
||||
menuitem->checked);
|
||||
}
|
||||
else if (menuitem->type == MENU_ITEM_RADIOBUTTON)
|
||||
{
|
||||
mi = gtk_check_menu_item_new ();
|
||||
|
||||
gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (mi),
|
||||
TRUE);
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
|
||||
menuitem->checked);
|
||||
}
|
||||
else if (menuitem->type == MENU_ITEM_WORKSPACE_LIST)
|
||||
return NULL;
|
||||
else
|
||||
return gtk_separator_menu_item_new ();
|
||||
|
||||
i18n_label = _(menuitem->label);
|
||||
meta_core_get_menu_accelerator (menuitem->op, workspace_id, &key, &mods);
|
||||
|
||||
accel_label = meta_accel_label_new_with_mnemonic (i18n_label);
|
||||
gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (mi), accel_label);
|
||||
gtk_widget_show (accel_label);
|
||||
|
||||
meta_accel_label_set_accelerator (META_ACCEL_LABEL (accel_label),
|
||||
key, mods);
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
MetaWindowMenu*
|
||||
meta_window_menu_new (MetaFrames *frames,
|
||||
MetaMenuOp ops,
|
||||
MetaMenuOp insensitive,
|
||||
Window client_xwindow,
|
||||
unsigned long active_workspace,
|
||||
int n_workspaces,
|
||||
MetaWindowMenuFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
int i;
|
||||
MetaWindowMenu *menu;
|
||||
|
||||
/* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */
|
||||
if (n_workspaces < 2)
|
||||
ops &= ~(META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES);
|
||||
else if (n_workspaces == 2)
|
||||
/* #151183: If we only have two workspaces, disable the menu listing them. */
|
||||
ops &= ~(META_MENU_OP_WORKSPACES);
|
||||
|
||||
menu = g_new (MetaWindowMenu, 1);
|
||||
menu->frames = frames;
|
||||
menu->client_xwindow = client_xwindow;
|
||||
menu->func = func;
|
||||
menu->data = data;
|
||||
menu->ops = ops;
|
||||
menu->insensitive = insensitive;
|
||||
|
||||
menu->menu = gtk_menu_new ();
|
||||
|
||||
gtk_menu_set_screen (GTK_MENU (menu->menu),
|
||||
gtk_widget_get_screen (GTK_WIDGET (frames)));
|
||||
|
||||
for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++)
|
||||
{
|
||||
MenuItem menuitem = menuitems[i];
|
||||
if (ops & menuitem.op || menuitem.op == 0)
|
||||
{
|
||||
GtkWidget *mi;
|
||||
MenuData *md;
|
||||
unsigned int key;
|
||||
MetaVirtualModifier mods;
|
||||
|
||||
mi = menu_item_new (&menuitem, -1);
|
||||
|
||||
/* Set the activeness of radiobuttons. */
|
||||
switch (menuitem.op)
|
||||
{
|
||||
case META_MENU_OP_STICK:
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
|
||||
active_workspace == 0xFFFFFFFF);
|
||||
break;
|
||||
case META_MENU_OP_UNSTICK:
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
|
||||
active_workspace != 0xFFFFFFFF);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (menuitem.type == MENU_ITEM_WORKSPACE_LIST)
|
||||
{
|
||||
if (ops & META_MENU_OP_WORKSPACES)
|
||||
{
|
||||
Display *display;
|
||||
Window xroot;
|
||||
GdkScreen *screen;
|
||||
GdkWindow *window;
|
||||
GtkWidget *submenu;
|
||||
int j;
|
||||
|
||||
MenuItem to_another_workspace = {
|
||||
0, MENU_ITEM_NORMAL, FALSE,
|
||||
N_("Move to Another _Workspace")
|
||||
};
|
||||
|
||||
meta_verbose ("Creating %d-workspace menu current space %lu\n",
|
||||
n_workspaces, active_workspace);
|
||||
|
||||
window = gtk_widget_get_window (GTK_WIDGET (frames));
|
||||
display = GDK_WINDOW_XDISPLAY (window);
|
||||
|
||||
screen = gdk_window_get_screen (window);
|
||||
xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
|
||||
|
||||
submenu = gtk_menu_new ();
|
||||
|
||||
g_assert (mi==NULL);
|
||||
mi = menu_item_new (&to_another_workspace, -1);
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu);
|
||||
|
||||
for (j = 0; j < n_workspaces; j++)
|
||||
{
|
||||
char *label;
|
||||
MenuData *md;
|
||||
unsigned int key;
|
||||
MetaVirtualModifier mods;
|
||||
MenuItem moveitem;
|
||||
GtkWidget *submi;
|
||||
|
||||
meta_core_get_menu_accelerator (META_MENU_OP_WORKSPACES,
|
||||
j + 1,
|
||||
&key, &mods);
|
||||
|
||||
label = get_workspace_name_with_accel (display, xroot, j);
|
||||
|
||||
moveitem.type = MENU_ITEM_NORMAL;
|
||||
moveitem.op = META_MENU_OP_WORKSPACES;
|
||||
moveitem.label = label;
|
||||
submi = menu_item_new (&moveitem, j + 1);
|
||||
|
||||
g_free (label);
|
||||
|
||||
if ((active_workspace == (unsigned)j) && (ops & META_MENU_OP_UNSTICK))
|
||||
gtk_widget_set_sensitive (submi, FALSE);
|
||||
|
||||
md = g_new (MenuData, 1);
|
||||
|
||||
md->menu = menu;
|
||||
md->op = META_MENU_OP_WORKSPACES;
|
||||
|
||||
g_object_set_data (G_OBJECT (submi),
|
||||
"workspace",
|
||||
GINT_TO_POINTER (j));
|
||||
|
||||
g_signal_connect_data (G_OBJECT (submi),
|
||||
"activate",
|
||||
G_CALLBACK (activate_cb),
|
||||
md,
|
||||
(GClosureNotify) g_free, 0);
|
||||
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), submi);
|
||||
|
||||
gtk_widget_show (submi);
|
||||
}
|
||||
}
|
||||
else
|
||||
meta_verbose ("not creating workspace menu\n");
|
||||
}
|
||||
else if (menuitem.type != MENU_ITEM_SEPARATOR)
|
||||
{
|
||||
meta_core_get_menu_accelerator (menuitems[i].op, -1,
|
||||
&key, &mods);
|
||||
|
||||
if (insensitive & menuitem.op)
|
||||
gtk_widget_set_sensitive (mi, FALSE);
|
||||
|
||||
md = g_new (MenuData, 1);
|
||||
|
||||
md->menu = menu;
|
||||
md->op = menuitem.op;
|
||||
|
||||
g_signal_connect_data (G_OBJECT (mi),
|
||||
"activate",
|
||||
G_CALLBACK (activate_cb),
|
||||
md,
|
||||
(GClosureNotify) g_free, 0);
|
||||
}
|
||||
|
||||
if (mi)
|
||||
{
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), mi);
|
||||
|
||||
gtk_widget_show (mi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
g_signal_connect (menu->menu, "selection_done",
|
||||
G_CALLBACK (menu_closed), menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_menu_popup (MetaWindowMenu *menu,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp)
|
||||
{
|
||||
GdkPoint *pt;
|
||||
|
||||
pt = g_new (GdkPoint, 1);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (menu->menu),
|
||||
"destroy-point",
|
||||
pt,
|
||||
g_free);
|
||||
|
||||
pt->x = root_x;
|
||||
pt->y = root_y;
|
||||
|
||||
gtk_menu_popup (GTK_MENU (menu->menu),
|
||||
NULL, NULL,
|
||||
popup_position_func, pt,
|
||||
button,
|
||||
timestamp);
|
||||
|
||||
if (!gtk_widget_get_visible (menu->menu))
|
||||
meta_warning ("GtkMenu failed to grab the pointer\n");
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_menu_free (MetaWindowMenu *menu)
|
||||
{
|
||||
gtk_widget_destroy (menu->menu);
|
||||
g_free (menu);
|
||||
}
|
55
src/ui/menu.h
Normal file
55
src/ui/menu.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/* Mutter window menu */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* 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_MENU_H
|
||||
#define META_MENU_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "frames.h"
|
||||
|
||||
struct _MetaWindowMenu
|
||||
{
|
||||
MetaFrames *frames;
|
||||
Window client_xwindow;
|
||||
GtkWidget *menu;
|
||||
MetaWindowMenuFunc func;
|
||||
gpointer data;
|
||||
MetaMenuOp ops;
|
||||
MetaMenuOp insensitive;
|
||||
};
|
||||
|
||||
MetaWindowMenu* meta_window_menu_new (MetaFrames *frames,
|
||||
MetaMenuOp ops,
|
||||
MetaMenuOp insensitive,
|
||||
Window client_xwindow,
|
||||
unsigned long active_workspace,
|
||||
int n_workspaces,
|
||||
MetaWindowMenuFunc func,
|
||||
gpointer data);
|
||||
void meta_window_menu_popup (MetaWindowMenu *menu,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp);
|
||||
void meta_window_menu_free (MetaWindowMenu *menu);
|
||||
|
||||
|
||||
#endif
|
451
src/ui/metaaccellabel.c
Normal file
451
src/ui/metaaccellabel.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/* Metacity hacked-up GtkAccelLabel */
|
||||
/* Copyright (C) 2002 Red Hat, Inc. */
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
|
||||
* Copyright (C) 1998 Tim Janik
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "metaaccellabel.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
#include "util-private.h"
|
||||
|
||||
static void meta_accel_label_destroy (GtkWidget *object);
|
||||
static void meta_accel_label_finalize (GObject *object);
|
||||
static void meta_accel_label_get_preferred_width (GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural);
|
||||
static void meta_accel_label_get_preferred_height (GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural);
|
||||
static gboolean meta_accel_label_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
|
||||
static void meta_accel_label_update (MetaAccelLabel *accel_label);
|
||||
static int meta_accel_label_get_accel_width (MetaAccelLabel *accel_label);
|
||||
|
||||
G_DEFINE_TYPE (MetaAccelLabel, meta_accel_label, GTK_TYPE_LABEL);
|
||||
|
||||
static void
|
||||
meta_accel_label_class_init (MetaAccelLabelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
gobject_class->finalize = meta_accel_label_finalize;
|
||||
|
||||
widget_class->destroy = meta_accel_label_destroy;
|
||||
|
||||
widget_class->get_preferred_width = meta_accel_label_get_preferred_width;
|
||||
widget_class->get_preferred_height = meta_accel_label_get_preferred_height;
|
||||
widget_class->draw = meta_accel_label_draw;
|
||||
|
||||
class->signal_quote1 = g_strdup ("<:");
|
||||
class->signal_quote2 = g_strdup (":>");
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the shift key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_shift = g_strdup (_("Shift"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the control key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_control = g_strdup (_("Ctrl"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the alt key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_alt = g_strdup (_("Alt"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the meta key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_meta = g_strdup (_("Meta"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the super key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_super = g_strdup (_("Super"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the hyper key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_hyper = g_strdup (_("Hyper"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the mod2 key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_mod2 = g_strdup (_("Mod2"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the mod3 key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_mod3 = g_strdup (_("Mod3"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the mod4 key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_mod4 = g_strdup (_("Mod4"));
|
||||
/* This is the text that should appear next to menu accelerators
|
||||
* that use the mod5 key. If the text on this key isn't typically
|
||||
* translated on keyboards used for your language, don't translate
|
||||
* this.
|
||||
*/
|
||||
class->mod_name_mod5 = g_strdup (_("Mod5"));
|
||||
|
||||
class->mod_separator = g_strdup ("+");
|
||||
class->accel_seperator = g_strdup (" / ");
|
||||
class->latin1_to_char = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_accel_label_init (MetaAccelLabel *accel_label)
|
||||
{
|
||||
accel_label->accel_padding = 3;
|
||||
accel_label->accel_string = NULL;
|
||||
|
||||
meta_accel_label_update (accel_label);
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
meta_accel_label_new_with_mnemonic (const gchar *string)
|
||||
{
|
||||
MetaAccelLabel *accel_label;
|
||||
|
||||
g_return_val_if_fail (string != NULL, NULL);
|
||||
|
||||
accel_label = g_object_new (META_TYPE_ACCEL_LABEL, NULL);
|
||||
|
||||
gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), string);
|
||||
|
||||
return GTK_WIDGET (accel_label);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_accel_label_destroy (GtkWidget *object)
|
||||
{
|
||||
MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
|
||||
|
||||
|
||||
g_free (accel_label->accel_string);
|
||||
accel_label->accel_string = NULL;
|
||||
|
||||
accel_label->accel_mods = 0;
|
||||
accel_label->accel_key = 0;
|
||||
|
||||
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->destroy (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_accel_label_finalize (GObject *object)
|
||||
{
|
||||
MetaAccelLabel *accel_label = META_ACCEL_LABEL (object);
|
||||
|
||||
g_free (accel_label->accel_string);
|
||||
|
||||
G_OBJECT_CLASS (meta_accel_label_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
void
|
||||
meta_accel_label_set_accelerator (MetaAccelLabel *accel_label,
|
||||
guint accelerator_key,
|
||||
MetaVirtualModifier accelerator_mods)
|
||||
{
|
||||
g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
|
||||
|
||||
if (accelerator_key != accel_label->accel_key ||
|
||||
accelerator_mods != accel_label->accel_mods)
|
||||
{
|
||||
accel_label->accel_mods = accelerator_mods;
|
||||
accel_label->accel_key = accelerator_key;
|
||||
|
||||
meta_accel_label_update (accel_label);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
meta_accel_label_get_accel_width (MetaAccelLabel *accel_label)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_ACCEL_LABEL (accel_label), 0);
|
||||
|
||||
return (accel_label->accel_string_width +
|
||||
(accel_label->accel_string_width ? accel_label->accel_padding : 0));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_accel_label_get_preferred_width (GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural)
|
||||
{
|
||||
MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
|
||||
PangoLayout *layout;
|
||||
gint width;
|
||||
|
||||
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_width (widget, minimum, natural);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
|
||||
pango_layout_get_pixel_size (layout, &width, NULL);
|
||||
accel_label->accel_string_width = width;
|
||||
|
||||
g_object_unref (G_OBJECT (layout));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_accel_label_get_preferred_height (GtkWidget *widget,
|
||||
gint *minimum,
|
||||
gint *natural)
|
||||
{
|
||||
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->get_preferred_height (widget, minimum, natural);
|
||||
}
|
||||
|
||||
/* Mostly taken from GTK3. */
|
||||
static gboolean
|
||||
meta_accel_label_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
MetaAccelLabel *accel_label = META_ACCEL_LABEL (widget);
|
||||
GtkMisc *misc = GTK_MISC (accel_label);
|
||||
GtkTextDirection direction;
|
||||
int ac_width;
|
||||
GtkAllocation allocation;
|
||||
GtkRequisition requisition;
|
||||
|
||||
direction = gtk_widget_get_direction (widget);
|
||||
ac_width = meta_accel_label_get_accel_width (accel_label);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_get_preferred_size (widget,
|
||||
&requisition, NULL);
|
||||
|
||||
if (allocation.width >= requisition.width + ac_width)
|
||||
{
|
||||
GtkStyleContext *style;
|
||||
PangoLayout *label_layout;
|
||||
PangoLayout *accel_layout;
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
gint x, y, xpad, ypad;
|
||||
gfloat xalign, yalign;
|
||||
|
||||
label_layout = gtk_label_get_layout (GTK_LABEL (accel_label));
|
||||
gtk_misc_get_alignment (misc, &xalign, &yalign);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
/* XXX: Mad hack: We modify the label's width so it renders
|
||||
* properly in its draw function that we chain to. */
|
||||
if (direction == GTK_TEXT_DIR_RTL)
|
||||
cairo_translate (cr, ac_width, 0);
|
||||
if (gtk_label_get_ellipsize (label))
|
||||
pango_layout_set_width (label_layout,
|
||||
pango_layout_get_width (label_layout)
|
||||
- ac_width * PANGO_SCALE);
|
||||
|
||||
allocation.width -= ac_width;
|
||||
gtk_widget_set_allocation (widget, &allocation);
|
||||
if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw)
|
||||
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget,
|
||||
cr);
|
||||
allocation.width += ac_width;
|
||||
gtk_widget_set_allocation (widget, &allocation);
|
||||
if (gtk_label_get_ellipsize (label))
|
||||
pango_layout_set_width (label_layout,
|
||||
pango_layout_get_width (label_layout)
|
||||
+ ac_width * PANGO_SCALE);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
gtk_misc_get_padding (misc, &xpad, &ypad);
|
||||
|
||||
if (direction == GTK_TEXT_DIR_RTL)
|
||||
x = xpad;
|
||||
else
|
||||
x = gtk_widget_get_allocated_width (widget) - xpad - ac_width;
|
||||
|
||||
gtk_label_get_layout_offsets (GTK_LABEL (accel_label), NULL, &y);
|
||||
|
||||
accel_layout = gtk_widget_create_pango_layout (widget, accel_label->accel_string);
|
||||
|
||||
y = (allocation.height - (requisition.height - ypad * 2)) * yalign + 1.5;
|
||||
|
||||
style = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_save (style);
|
||||
gtk_style_context_set_state (style,
|
||||
gtk_widget_get_state_flags (widget));
|
||||
gtk_render_layout (gtk_widget_get_style_context (widget),
|
||||
cr,
|
||||
x, y,
|
||||
accel_layout);
|
||||
gtk_style_context_restore (style);
|
||||
|
||||
g_object_unref (accel_layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw)
|
||||
GTK_WIDGET_CLASS (meta_accel_label_parent_class)->draw (widget, cr);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_accel_label_update (MetaAccelLabel *accel_label)
|
||||
{
|
||||
MetaAccelLabelClass *class;
|
||||
GString *gstring;
|
||||
gboolean seen_mod = FALSE;
|
||||
gunichar ch;
|
||||
|
||||
g_return_if_fail (META_IS_ACCEL_LABEL (accel_label));
|
||||
|
||||
class = META_ACCEL_LABEL_GET_CLASS (accel_label);
|
||||
|
||||
g_free (accel_label->accel_string);
|
||||
accel_label->accel_string = NULL;
|
||||
|
||||
gstring = g_string_new (accel_label->accel_string);
|
||||
g_string_append (gstring, gstring->len ? class->accel_seperator : " ");
|
||||
|
||||
if (accel_label->accel_mods & META_VIRTUAL_SHIFT_MASK)
|
||||
{
|
||||
g_string_append (gstring, class->mod_name_shift);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_CONTROL_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_control);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_ALT_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_alt);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_META_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_meta);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_SUPER_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_super);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_HYPER_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_hyper);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_MOD2_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_mod2);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_MOD3_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_mod3);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_MOD4_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_mod4);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
if (accel_label->accel_mods & META_VIRTUAL_MOD5_MASK)
|
||||
{
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
g_string_append (gstring, class->mod_name_mod5);
|
||||
seen_mod = TRUE;
|
||||
}
|
||||
|
||||
if (seen_mod)
|
||||
g_string_append (gstring, class->mod_separator);
|
||||
|
||||
ch = gdk_keyval_to_unicode (accel_label->accel_key);
|
||||
if (ch && (g_unichar_isgraph (ch) || ch == ' ') &&
|
||||
(ch < 0x80 || class->latin1_to_char))
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case ' ':
|
||||
g_string_append (gstring, "Space");
|
||||
break;
|
||||
case '\\':
|
||||
g_string_append (gstring, "Backslash");
|
||||
break;
|
||||
default:
|
||||
g_string_append_unichar (gstring, g_unichar_toupper (ch));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *tmp;
|
||||
|
||||
tmp = gtk_accelerator_name (accel_label->accel_key, 0);
|
||||
if (tmp[0] != 0 && tmp[1] == 0)
|
||||
tmp[0] = g_ascii_toupper (tmp[0]);
|
||||
g_string_append (gstring, tmp);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
g_free (accel_label->accel_string);
|
||||
accel_label->accel_string = gstring->str;
|
||||
g_string_free (gstring, FALSE);
|
||||
|
||||
g_assert (accel_label->accel_string);
|
||||
/* accel_label->accel_string = g_strdup ("-/-"); */
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (accel_label));
|
||||
}
|
104
src/ui/metaaccellabel.h
Normal file
104
src/ui/metaaccellabel.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/* Metacity hacked-up GtkAccelLabel */
|
||||
/* Copyright (C) 2002 Red Hat, Inc. */
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* MetaAccelLabel: GtkLabel with accelerator monitoring facilities.
|
||||
* Copyright (C) 1998 Tim Janik
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#ifndef __META_ACCEL_LABEL_H__
|
||||
#define __META_ACCEL_LABEL_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <meta/common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#define META_TYPE_ACCEL_LABEL (meta_accel_label_get_type ())
|
||||
#define META_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabel))
|
||||
#define META_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass))
|
||||
#define META_IS_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_ACCEL_LABEL))
|
||||
#define META_IS_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_ACCEL_LABEL))
|
||||
#define META_ACCEL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_ACCEL_LABEL, MetaAccelLabelClass))
|
||||
|
||||
|
||||
typedef struct _MetaAccelLabel MetaAccelLabel;
|
||||
typedef struct _MetaAccelLabelClass MetaAccelLabelClass;
|
||||
|
||||
struct _MetaAccelLabel
|
||||
{
|
||||
GtkLabel label;
|
||||
|
||||
MetaVirtualModifier accel_mods;
|
||||
guint accel_key;
|
||||
guint accel_padding;
|
||||
gchar *accel_string;
|
||||
guint16 accel_string_width;
|
||||
};
|
||||
|
||||
struct _MetaAccelLabelClass
|
||||
{
|
||||
GtkLabelClass parent_class;
|
||||
|
||||
gchar *signal_quote1;
|
||||
gchar *signal_quote2;
|
||||
gchar *mod_name_shift;
|
||||
gchar *mod_name_control;
|
||||
gchar *mod_name_alt;
|
||||
gchar *mod_name_meta;
|
||||
gchar *mod_name_super;
|
||||
gchar *mod_name_hyper;
|
||||
gchar *mod_name_mod2;
|
||||
gchar *mod_name_mod3;
|
||||
gchar *mod_name_mod4;
|
||||
gchar *mod_name_mod5;
|
||||
gchar *mod_separator;
|
||||
gchar *accel_seperator;
|
||||
guint latin1_to_char : 1;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
GType meta_accel_label_get_type (void) G_GNUC_CONST;
|
||||
GtkWidget* meta_accel_label_new_with_mnemonic (const gchar *string);
|
||||
void meta_accel_label_set_accelerator (MetaAccelLabel *accel_label,
|
||||
guint accelerator_key,
|
||||
MetaVirtualModifier accelerator_mods);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __META_ACCEL_LABEL_H__ */
|
34
src/ui/ui.c
34
src/ui/ui.c
@@ -514,6 +514,40 @@ meta_ui_set_frame_title (MetaUI *ui,
|
||||
meta_frames_set_title (ui->frames, xwindow, title);
|
||||
}
|
||||
|
||||
MetaWindowMenu*
|
||||
meta_ui_window_menu_new (MetaUI *ui,
|
||||
Window client_xwindow,
|
||||
MetaMenuOp ops,
|
||||
MetaMenuOp insensitive,
|
||||
unsigned long active_workspace,
|
||||
int n_workspaces,
|
||||
MetaWindowMenuFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
return meta_window_menu_new (ui->frames,
|
||||
ops, insensitive,
|
||||
client_xwindow,
|
||||
active_workspace,
|
||||
n_workspaces,
|
||||
func, data);
|
||||
}
|
||||
|
||||
void
|
||||
meta_ui_window_menu_popup (MetaWindowMenu *menu,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp)
|
||||
{
|
||||
meta_window_menu_popup (menu, root_x, root_y, button, timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
meta_ui_window_menu_free (MetaWindowMenu *menu)
|
||||
{
|
||||
meta_window_menu_free (menu);
|
||||
}
|
||||
|
||||
GdkPixbuf*
|
||||
meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap,
|
||||
int src_x,
|
||||
|
15
src/ui/ui.h
15
src/ui/ui.h
@@ -120,6 +120,21 @@ void meta_ui_update_frame_style (MetaUI *ui,
|
||||
void meta_ui_repaint_frame (MetaUI *ui,
|
||||
Window xwindow);
|
||||
|
||||
MetaWindowMenu* meta_ui_window_menu_new (MetaUI *ui,
|
||||
Window client_xwindow,
|
||||
MetaMenuOp ops,
|
||||
MetaMenuOp insensitive,
|
||||
unsigned long active_workspace,
|
||||
int n_workspaces,
|
||||
MetaWindowMenuFunc func,
|
||||
gpointer data);
|
||||
void meta_ui_window_menu_popup (MetaWindowMenu *menu,
|
||||
int root_x,
|
||||
int root_y,
|
||||
int button,
|
||||
guint32 timestamp);
|
||||
void meta_ui_window_menu_free (MetaWindowMenu *menu);
|
||||
|
||||
|
||||
/* FIXME these lack a display arg */
|
||||
GdkPixbuf* meta_gdk_pixbuf_get_from_pixmap (Pixmap xpixmap,
|
||||
|
@@ -1,441 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-login1.h"
|
||||
|
||||
#include "meta-dbus-login1.h"
|
||||
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/evdev/clutter-evdev.h>
|
||||
#include <clutter/egl/clutter-egl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <malloc.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <systemd/sd-login.h>
|
||||
|
||||
struct _MetaLogin1
|
||||
{
|
||||
Login1Session *session_proxy;
|
||||
Login1Seat *seat_proxy;
|
||||
|
||||
gboolean session_active;
|
||||
};
|
||||
|
||||
/* Stolen from tp_escape_as_identifier, from tp-glib,
|
||||
* which follows the same escaping convention as systemd.
|
||||
*/
|
||||
static inline gboolean
|
||||
_esc_ident_bad (gchar c, gboolean is_first)
|
||||
{
|
||||
return ((c < 'a' || c > 'z') &&
|
||||
(c < 'A' || c > 'Z') &&
|
||||
(c < '0' || c > '9' || is_first));
|
||||
}
|
||||
|
||||
static gchar *
|
||||
escape_dbus_component (const gchar *name)
|
||||
{
|
||||
gboolean bad = FALSE;
|
||||
size_t len = 0;
|
||||
GString *op;
|
||||
const gchar *ptr, *first_ok;
|
||||
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
/* fast path for empty name */
|
||||
if (name[0] == '\0')
|
||||
return g_strdup ("_");
|
||||
|
||||
for (ptr = name; *ptr; ptr++)
|
||||
{
|
||||
if (_esc_ident_bad (*ptr, ptr == name))
|
||||
{
|
||||
bad = TRUE;
|
||||
len += 3;
|
||||
}
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
/* fast path if it's clean */
|
||||
if (!bad)
|
||||
return g_strdup (name);
|
||||
|
||||
/* If strictly less than ptr, first_ok is the first uncopied safe character.
|
||||
*/
|
||||
first_ok = name;
|
||||
op = g_string_sized_new (len);
|
||||
for (ptr = name; *ptr; ptr++)
|
||||
{
|
||||
if (_esc_ident_bad (*ptr, ptr == name))
|
||||
{
|
||||
/* copy preceding safe characters if any */
|
||||
if (first_ok < ptr)
|
||||
{
|
||||
g_string_append_len (op, first_ok, ptr - first_ok);
|
||||
}
|
||||
/* escape the unsafe character */
|
||||
g_string_append_printf (op, "_%02x", (unsigned char)(*ptr));
|
||||
/* restart after it */
|
||||
first_ok = ptr + 1;
|
||||
}
|
||||
}
|
||||
/* copy trailing safe characters if any */
|
||||
if (first_ok < ptr)
|
||||
{
|
||||
g_string_append_len (op, first_ok, ptr - first_ok);
|
||||
}
|
||||
return g_string_free (op, FALSE);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_escaped_dbus_path (const char *prefix,
|
||||
const char *component)
|
||||
{
|
||||
char *escaped_component = escape_dbus_component (component);
|
||||
char *path = g_strconcat (prefix, "/", component, NULL);
|
||||
|
||||
g_free (escaped_component);
|
||||
return path;
|
||||
}
|
||||
|
||||
static Login1Session *
|
||||
get_session_proxy (GCancellable *cancellable)
|
||||
{
|
||||
char *proxy_path;
|
||||
char *session_id;
|
||||
Login1Session *session_proxy;
|
||||
|
||||
if (sd_pid_get_session (getpid (), &session_id) < 0)
|
||||
return NULL;
|
||||
|
||||
proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
|
||||
|
||||
session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
"org.freedesktop.login1",
|
||||
proxy_path,
|
||||
cancellable, NULL);
|
||||
free (proxy_path);
|
||||
|
||||
return session_proxy;
|
||||
}
|
||||
|
||||
static Login1Seat *
|
||||
get_seat_proxy (GCancellable *cancellable)
|
||||
{
|
||||
return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1/seat/self",
|
||||
cancellable, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
session_unpause (void)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_kms_display_queue_modes_reset (cogl_display);
|
||||
|
||||
clutter_set_paused (FALSE);
|
||||
/* clutter_evdev_reclaim_devices (); */
|
||||
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
/* When we mode-switch back, we need to immediately queue a redraw
|
||||
* in case nothing else quueed one for us, and force the cursor to
|
||||
* update. */
|
||||
|
||||
clutter_actor_queue_redraw (compositor->stage);
|
||||
meta_cursor_tracker_force_update (compositor->seat->cursor_tracker);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
session_pause (void)
|
||||
{
|
||||
clutter_set_paused (TRUE);
|
||||
/* clutter_evdev_release_devices (); */
|
||||
}
|
||||
|
||||
static void
|
||||
sync_active (MetaLogin1 *self)
|
||||
{
|
||||
gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
|
||||
|
||||
if (active == self->session_active)
|
||||
return;
|
||||
|
||||
self->session_active = active;
|
||||
|
||||
if (active)
|
||||
session_unpause ();
|
||||
else
|
||||
session_pause ();
|
||||
}
|
||||
|
||||
static void
|
||||
on_active_changed (Login1Session *session,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLogin1 *self = user_data;
|
||||
sync_active (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
take_device (Login1Session *session_proxy,
|
||||
int dev_major,
|
||||
int dev_minor,
|
||||
int *out_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GVariant *fd_variant = NULL;
|
||||
int fd = -1;
|
||||
GUnixFDList *fd_list;
|
||||
|
||||
if (!login1_session_call_take_device_sync (session_proxy,
|
||||
dev_major,
|
||||
dev_minor,
|
||||
NULL,
|
||||
&fd_variant,
|
||||
NULL, /* paused */
|
||||
&fd_list,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
|
||||
if (fd == -1)
|
||||
goto out;
|
||||
|
||||
*out_fd = fd;
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (fd_variant)
|
||||
g_variant_unref (fd_variant);
|
||||
if (fd_list)
|
||||
g_object_unref (fd_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_device_info_from_path (const char *path,
|
||||
int *out_major,
|
||||
int *out_minor)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int r;
|
||||
struct stat st;
|
||||
|
||||
r = stat (path, &st);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (!S_ISCHR (st.st_mode))
|
||||
goto out;
|
||||
|
||||
*out_major = major (st.st_rdev);
|
||||
*out_minor = minor (st.st_rdev);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_device_info_from_fd (int fd,
|
||||
int *out_major,
|
||||
int *out_minor)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int r;
|
||||
struct stat st;
|
||||
|
||||
r = fstat (fd, &st);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (!S_ISCHR (st.st_mode))
|
||||
goto out;
|
||||
|
||||
*out_major = major (st.st_rdev);
|
||||
*out_minor = minor (st.st_rdev);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
open_evdev_device (const char *path,
|
||||
int flags,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaLogin1 *self = user_data;
|
||||
int fd;
|
||||
int major, minor;
|
||||
|
||||
if (!get_device_info_from_path (path, &major, &minor))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_FOUND,
|
||||
"Could not get device info for path %s: %m", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
|
||||
return -1;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
close_evdev_device (int fd,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLogin1 *self = user_data;
|
||||
int major, minor;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!get_device_info_from_fd (fd, &major, &minor))
|
||||
{
|
||||
g_warning ("Could not get device info for fd %d: %m", fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!login1_session_call_release_device_sync (self->session_proxy,
|
||||
major, minor,
|
||||
NULL, &error))
|
||||
{
|
||||
g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_kms_fd (Login1Session *session_proxy,
|
||||
int *fd_out)
|
||||
{
|
||||
int major, minor;
|
||||
int fd;
|
||||
GError *error = NULL;
|
||||
|
||||
/* XXX -- use udev to find the DRM master device */
|
||||
if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
|
||||
{
|
||||
g_warning ("Could not stat /dev/dri/card0: %m");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
|
||||
{
|
||||
g_warning ("Could not open DRM device: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*fd_out = fd;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaLogin1 *
|
||||
meta_login1_new (void)
|
||||
{
|
||||
MetaLogin1 *self;
|
||||
Login1Session *session_proxy;
|
||||
GError *error = NULL;
|
||||
int kms_fd;
|
||||
|
||||
session_proxy = get_session_proxy (NULL);
|
||||
if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
|
||||
{
|
||||
g_warning ("Could not take control: %s", error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!get_kms_fd (session_proxy, &kms_fd))
|
||||
return NULL;
|
||||
|
||||
self = g_slice_new0 (MetaLogin1);
|
||||
self->session_proxy = session_proxy;
|
||||
self->seat_proxy = get_seat_proxy (NULL);
|
||||
|
||||
/* Clutter/Cogl start out in a state that assumes the session is active */
|
||||
self->session_active = TRUE;
|
||||
|
||||
clutter_egl_set_kms_fd (kms_fd);
|
||||
clutter_evdev_set_device_callbacks (open_evdev_device,
|
||||
close_evdev_device,
|
||||
self);
|
||||
|
||||
g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
|
||||
sync_active (self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
meta_login1_free (MetaLogin1 *self)
|
||||
{
|
||||
g_object_unref (self->seat_proxy);
|
||||
g_object_unref (self->session_proxy);
|
||||
g_slice_free (MetaLogin1, self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_login1_activate_session (MetaLogin1 *self,
|
||||
GError **error)
|
||||
{
|
||||
if (!login1_session_call_activate_sync (self->session_proxy, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
sync_active (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_login1_activate_vt (MetaLogin1 *self,
|
||||
int vt,
|
||||
GError **error)
|
||||
{
|
||||
return login1_seat_call_switch_to_sync (self->seat_proxy, vt, NULL, error);
|
||||
}
|
@@ -175,8 +175,7 @@ destroy_drag_focus (struct wl_listener *listener, void *data)
|
||||
|
||||
static void
|
||||
drag_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
const ClutterEvent *event)
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
|
||||
MetaWaylandSeat *seat = drag_grab->seat;
|
||||
@@ -257,7 +256,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, NULL);
|
||||
drag_grab_focus (&drag_grab->generic, NULL);
|
||||
|
||||
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
|
||||
g_slice_free (MetaWaylandDragGrab, drag_grab);
|
||||
|
@@ -138,10 +138,12 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
|
||||
return;
|
||||
}
|
||||
|
||||
if (xkb_info->keymap)
|
||||
xkb_keymap_unref (xkb_info->keymap);
|
||||
xkb_keymap_unref (xkb_info->keymap);
|
||||
xkb_info->keymap = keymap;
|
||||
|
||||
xkb_state_unref (xkb_info->state);
|
||||
xkb_info->state = xkb_state_new (keymap);
|
||||
|
||||
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
|
||||
if (keymap_str == NULL)
|
||||
{
|
||||
@@ -316,8 +318,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
||||
static void
|
||||
meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
|
||||
{
|
||||
if (xkb_info->keymap)
|
||||
xkb_map_unref (xkb_info->keymap);
|
||||
xkb_keymap_unref (xkb_info->keymap);
|
||||
xkb_state_unref (xkb_info->state);
|
||||
|
||||
if (xkb_info->keymap_area)
|
||||
munmap (xkb_info->keymap_area, xkb_info->keymap_size);
|
||||
@@ -325,47 +327,7 @@ meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
|
||||
close (xkb_info->keymap_fd);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
state_equal (MetaWaylandXkbState *one,
|
||||
MetaWaylandXkbState *two)
|
||||
{
|
||||
return one->mods_depressed == two->mods_depressed &&
|
||||
one->mods_latched == two->mods_latched &&
|
||||
one->mods_locked == two->mods_locked &&
|
||||
one->group == two->group;
|
||||
}
|
||||
|
||||
static void
|
||||
set_modifiers (MetaWaylandKeyboard *keyboard,
|
||||
guint32 serial,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
MetaWaylandKeyboardGrab *grab = keyboard->grab;
|
||||
MetaWaylandXkbState new_state;
|
||||
guint effective_state;
|
||||
|
||||
clutter_event_get_state_full (event,
|
||||
NULL,
|
||||
&new_state.mods_depressed,
|
||||
&new_state.mods_latched,
|
||||
&new_state.mods_locked,
|
||||
&effective_state);
|
||||
new_state.group = (effective_state >> 13) & 0x3;
|
||||
|
||||
if (state_equal (&keyboard->modifier_state, &new_state))
|
||||
return;
|
||||
|
||||
keyboard->modifier_state = new_state;
|
||||
|
||||
grab->interface->modifiers (grab,
|
||||
serial,
|
||||
new_state.mods_depressed,
|
||||
new_state.mods_latched,
|
||||
new_state.mods_locked,
|
||||
new_state.group);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_pressed_keys (MetaWaylandKeyboard *keyboard,
|
||||
uint32_t evdev_code,
|
||||
gboolean is_press)
|
||||
@@ -376,13 +338,10 @@ update_pressed_keys (MetaWaylandKeyboard *keyboard,
|
||||
keyboard->keys.size);
|
||||
uint32_t *k;
|
||||
|
||||
/* We want to ignore events that are sent because of auto-repeat. In
|
||||
the Clutter event stream these appear as a single key press
|
||||
event. We can detect that because the key will already have been
|
||||
pressed */
|
||||
/* Make sure we don't already have this key. */
|
||||
for (k = keyboard->keys.data; k < end; k++)
|
||||
if (*k == evdev_code)
|
||||
return TRUE;
|
||||
return;
|
||||
|
||||
/* Otherwise add the key to the list of pressed keys */
|
||||
k = wl_array_add (&keyboard->keys, sizeof (*k));
|
||||
@@ -400,18 +359,44 @@ update_pressed_keys (MetaWaylandKeyboard *keyboard,
|
||||
{
|
||||
*k = *(end - 1);
|
||||
keyboard->keys.size -= sizeof (*k);
|
||||
|
||||
goto found;
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("unexpected key release event for key 0x%x", evdev_code);
|
||||
return FALSE;
|
||||
|
||||
found:
|
||||
(void) 0;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
static guint
|
||||
evdev_code (const ClutterKeyEvent *event)
|
||||
{
|
||||
/* clutter-xkb-utils.c adds a fixed offset of 8 to go into XKB's
|
||||
* range, so we do the reverse here. */
|
||||
return event->hardware_keycode - 8;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterKeyEvent *event)
|
||||
{
|
||||
MetaWaylandKeyboardGrab *grab = keyboard->grab;
|
||||
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
|
||||
struct xkb_state *state = keyboard->xkb_info.state;
|
||||
enum xkb_state_component changed_state;
|
||||
|
||||
update_pressed_keys (keyboard, evdev_code (event), is_press);
|
||||
|
||||
changed_state = xkb_state_update_key (state,
|
||||
event->hardware_keycode,
|
||||
is_press ? XKB_KEY_DOWN : XKB_KEY_UP);
|
||||
if (changed_state == 0)
|
||||
return;
|
||||
|
||||
grab->interface->modifiers (grab,
|
||||
wl_display_next_serial (keyboard->display),
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
|
||||
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -419,34 +404,20 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterKeyEvent *event)
|
||||
{
|
||||
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
|
||||
guint xkb_keycode, evdev_code;
|
||||
uint32_t serial;
|
||||
gboolean autorepeat;
|
||||
gboolean handled;
|
||||
|
||||
xkb_keycode = event->hardware_keycode;
|
||||
if (event->device == NULL ||
|
||||
!clutter_input_device_keycode_to_evdev (event->device,
|
||||
xkb_keycode, &evdev_code))
|
||||
evdev_code = xkb_keycode - 8; /* What everyone is doing in practice... */
|
||||
|
||||
autorepeat = update_pressed_keys (keyboard, evdev_code, is_press);
|
||||
|
||||
meta_verbose ("Handling key %s%s event code %d\n",
|
||||
is_press ? "press" : "release",
|
||||
autorepeat ? " (autorepeat)" : "",
|
||||
xkb_keycode);
|
||||
|
||||
if (autorepeat)
|
||||
/* Synthetic key events are for autorepeat. Ignore those, as
|
||||
* autorepeat in Wayland is done on the client side. */
|
||||
if (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC)
|
||||
return FALSE;
|
||||
|
||||
serial = wl_display_next_serial (keyboard->display);
|
||||
|
||||
set_modifiers (keyboard, serial, (ClutterEvent*)event);
|
||||
meta_verbose ("Handling key %s event code %d\n",
|
||||
is_press ? "press" : "release",
|
||||
event->hardware_keycode);
|
||||
|
||||
handled = keyboard->grab->interface->key (keyboard->grab,
|
||||
event->time,
|
||||
evdev_code,
|
||||
evdev_code (event),
|
||||
is_press);
|
||||
|
||||
if (handled)
|
||||
@@ -494,13 +465,14 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
||||
{
|
||||
struct wl_client *client = wl_resource_get_client (keyboard->focus_resource);
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
struct xkb_state *state = keyboard->xkb_info.state;
|
||||
uint32_t serial = wl_display_next_serial (display);
|
||||
|
||||
wl_keyboard_send_modifiers (keyboard->focus_resource, serial,
|
||||
keyboard->modifier_state.mods_depressed,
|
||||
keyboard->modifier_state.mods_latched,
|
||||
keyboard->modifier_state.mods_locked,
|
||||
keyboard->modifier_state.group);
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
|
||||
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
|
||||
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource,
|
||||
&keyboard->keys);
|
||||
|
||||
|
@@ -69,19 +69,12 @@ struct _MetaWaylandKeyboardGrab
|
||||
typedef struct
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
int keymap_fd;
|
||||
size_t keymap_size;
|
||||
char *keymap_area;
|
||||
} MetaWaylandXkbInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t mods_depressed;
|
||||
uint32_t mods_latched;
|
||||
uint32_t mods_locked;
|
||||
uint32_t group;
|
||||
} MetaWaylandXkbState;
|
||||
|
||||
struct _MetaWaylandKeyboard
|
||||
{
|
||||
struct wl_list resource_list;
|
||||
@@ -100,8 +93,6 @@ struct _MetaWaylandKeyboard
|
||||
|
||||
struct wl_array keys;
|
||||
|
||||
MetaWaylandXkbState modifier_state;
|
||||
|
||||
struct wl_display *display;
|
||||
|
||||
struct xkb_context *xkb_context;
|
||||
@@ -145,4 +136,8 @@ meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
|
||||
void
|
||||
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterKeyEvent *event);
|
||||
|
||||
#endif /* __META_WAYLAND_KEYBOARD_H__ */
|
||||
|
@@ -78,8 +78,7 @@ pointer_handle_focus_resource_destroy (struct wl_listener *listener, void *data)
|
||||
|
||||
static void
|
||||
default_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
const ClutterEvent *event)
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandPointer *pointer = grab->pointer;
|
||||
|
||||
@@ -385,7 +384,7 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
|
||||
grab->pointer = pointer;
|
||||
|
||||
if (pointer->current)
|
||||
interface->focus (pointer->grab, pointer->current, NULL);
|
||||
interface->focus (pointer->grab, pointer->current);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -395,7 +394,7 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
|
||||
|
||||
pointer->grab = &pointer->default_grab;
|
||||
interface = pointer->grab->interface;
|
||||
interface->focus (pointer->grab, pointer->current, NULL);
|
||||
interface->focus (pointer->grab, pointer->current);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@@ -415,15 +414,14 @@ typedef struct {
|
||||
|
||||
static void
|
||||
popup_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
const ClutterEvent *event)
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
|
||||
|
||||
/* Popup grabs are in owner-events mode (ie, events for the same client
|
||||
are reported as normal) */
|
||||
if (surface && wl_resource_get_client (surface->resource) == popup_grab->grab_client)
|
||||
default_grab_focus (grab, surface, event);
|
||||
default_grab_focus (grab, surface);
|
||||
else
|
||||
meta_wayland_pointer_set_focus (grab->pointer, NULL);
|
||||
}
|
||||
|
@@ -29,8 +29,7 @@
|
||||
struct _MetaWaylandPointerGrabInterface
|
||||
{
|
||||
void (*focus) (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
const ClutterEvent *event);
|
||||
MetaWaylandSurface *surface);
|
||||
void (*motion) (MetaWaylandPointerGrab *grab,
|
||||
const ClutterEvent *event);
|
||||
void (*button) (MetaWaylandPointerGrab *grab,
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include <cairo.h>
|
||||
|
||||
#include "window-private.h"
|
||||
#include "meta-login1.h"
|
||||
#include "meta-weston-launch.h"
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
|
||||
#include "meta-wayland.h"
|
||||
@@ -85,7 +85,7 @@ struct _MetaWaylandCompositor
|
||||
|
||||
MetaXWaylandManager xwayland_manager;
|
||||
|
||||
MetaLogin1 *login1;
|
||||
MetaLauncher *launcher;
|
||||
|
||||
MetaWaylandSeat *seat;
|
||||
};
|
||||
|
@@ -347,7 +347,7 @@ count_buttons (const ClutterEvent *event)
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
@@ -370,6 +370,27 @@ meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_seat_update (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_MOTION:
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
case CLUTTER_SCROLL:
|
||||
meta_wayland_seat_update_pointer (seat, event);
|
||||
break;
|
||||
case CLUTTER_KEY_PRESS:
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
meta_wayland_keyboard_update (&seat->keyboard, (const ClutterKeyEvent *) event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event)
|
||||
@@ -440,8 +461,7 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
|
||||
{
|
||||
const MetaWaylandPointerGrabInterface *interface =
|
||||
pointer->grab->interface;
|
||||
interface->focus (pointer->grab,
|
||||
surface, for_event);
|
||||
interface->focus (pointer->grab, surface);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -71,8 +71,8 @@ MetaWaylandSeat *
|
||||
meta_wayland_seat_new (struct wl_display *display);
|
||||
|
||||
void
|
||||
meta_wayland_seat_update_pointer (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event);
|
||||
meta_wayland_seat_update (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event);
|
||||
|
||||
gboolean
|
||||
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
|
||||
|
@@ -749,49 +749,6 @@ xdg_surface_set_app_id (struct wl_client *client,
|
||||
meta_window_set_wm_class (surface->window, app_id, app_id);
|
||||
}
|
||||
|
||||
static MetaWindowType
|
||||
window_type_from_surface_type (uint32_t surface_type)
|
||||
{
|
||||
switch (surface_type)
|
||||
{
|
||||
case XDG_SURFACE_SURFACE_TYPE_NORMAL:
|
||||
return META_WINDOW_NORMAL;
|
||||
case XDG_SURFACE_SURFACE_TYPE_MODAL_DIALOG:
|
||||
return META_WINDOW_MODAL_DIALOG;
|
||||
default:
|
||||
g_warning ("Unknown surface type: %d\n", surface_type);
|
||||
return META_WINDOW_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_surface_set_surface_type (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t surface_type)
|
||||
{
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||
|
||||
meta_window_set_type (surface->window,
|
||||
window_type_from_surface_type (surface_type));
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_surface_show_window_menu (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *seat_resource,
|
||||
uint32_t serial)
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||
|
||||
if (seat->pointer.button_count == 0 ||
|
||||
seat->pointer.grab_serial != serial ||
|
||||
seat->pointer.focus_surface != surface)
|
||||
return;
|
||||
|
||||
meta_window_show_menu (surface->window);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
begin_grab_op_on_surface (MetaWaylandSurface *surface,
|
||||
MetaWaylandSeat *seat,
|
||||
@@ -941,8 +898,6 @@ static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = {
|
||||
xdg_surface_set_margin,
|
||||
xdg_surface_set_title,
|
||||
xdg_surface_set_app_id,
|
||||
xdg_surface_set_surface_type,
|
||||
xdg_surface_show_window_menu,
|
||||
xdg_surface_move,
|
||||
xdg_surface_resize,
|
||||
xdg_surface_set_output,
|
||||
|
@@ -52,7 +52,7 @@
|
||||
#include <meta/main.h>
|
||||
#include "frame.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-login1.h"
|
||||
#include "meta-weston-launch.h"
|
||||
#include "monitor-private.h"
|
||||
|
||||
static MetaWaylandCompositor _meta_wayland_compositor;
|
||||
@@ -508,6 +508,15 @@ stage_destroy_cb (void)
|
||||
meta_quit (META_EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_wayland_compositor_update:
|
||||
* @compositor: the #MetaWaylandCompositor instance
|
||||
* @event: the #ClutterEvent used to update @seat's state
|
||||
*
|
||||
* This is used to update display server state like updating cursor
|
||||
* position and keeping track of buttons and keys pressed. It must be
|
||||
* called for all input events coming from the underlying devices.
|
||||
*/
|
||||
void
|
||||
meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
|
||||
const ClutterEvent *event)
|
||||
@@ -536,18 +545,18 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
|
||||
meta_idle_monitor_reset_idletime (device_monitor);
|
||||
}
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_MOTION:
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
case CLUTTER_SCROLL:
|
||||
meta_wayland_seat_update_pointer (compositor->seat, event);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
meta_wayland_seat_update (compositor->seat, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_wayland_compositor_handle_event:
|
||||
* @compositor: the #MetaWaylandCompositor instance
|
||||
* @event: the #ClutterEvent to be sent
|
||||
*
|
||||
* This method sends events to the focused wayland client, if any.
|
||||
*
|
||||
* Return value: whether @event was sent to a wayland client.
|
||||
*/
|
||||
gboolean
|
||||
meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
||||
const ClutterEvent *event)
|
||||
@@ -644,10 +653,10 @@ meta_wayland_init (void)
|
||||
clutter_wayland_set_compositor_display (compositor->wayland_display);
|
||||
|
||||
/* If we're running on bare metal, we're a display server,
|
||||
* so start talking to logind. */
|
||||
* so start talking to weston-launch. */
|
||||
#if defined(CLUTTER_WINDOWING_EGL)
|
||||
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
|
||||
compositor->login1 = meta_login1_new ();
|
||||
compositor->launcher = meta_launcher_new ();
|
||||
#endif
|
||||
|
||||
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
||||
@@ -704,8 +713,8 @@ meta_wayland_finalize (void)
|
||||
|
||||
meta_xwayland_stop (&compositor->xwayland_manager);
|
||||
|
||||
if (compositor->login1)
|
||||
meta_login1_free (compositor->login1);
|
||||
if (compositor->launcher)
|
||||
meta_launcher_free (compositor->launcher);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -713,9 +722,9 @@ meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
|
||||
int vt,
|
||||
GError **error)
|
||||
{
|
||||
if (compositor->login1)
|
||||
if (compositor->launcher)
|
||||
{
|
||||
return meta_login1_activate_vt (compositor->login1, vt, error);
|
||||
return meta_launcher_activate_vt (compositor->launcher, vt, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -728,9 +737,9 @@ gboolean
|
||||
meta_wayland_compositor_activate_session (MetaWaylandCompositor *compositor,
|
||||
GError **error)
|
||||
{
|
||||
if (compositor->login1)
|
||||
if (compositor->launcher)
|
||||
{
|
||||
return meta_login1_activate_session (compositor->login1, error);
|
||||
return meta_launcher_activate_vt (compositor->launcher, -1, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
411
src/wayland/meta-weston-launch.c
Normal file
411
src/wayland/meta-weston-launch.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixfdmessage.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/egl/clutter-egl.h>
|
||||
#include <clutter/evdev/clutter-evdev.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <drm.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "meta-weston-launch.h"
|
||||
|
||||
struct _MetaLauncher
|
||||
{
|
||||
GSocket *weston_launch;
|
||||
|
||||
gboolean vt_switched;
|
||||
|
||||
GMainContext *nested_context;
|
||||
GMainLoop *nested_loop;
|
||||
|
||||
GSource *inner_source;
|
||||
GSource *outer_source;
|
||||
};
|
||||
|
||||
static void handle_request_vt_switch (MetaLauncher *self);
|
||||
|
||||
static gboolean
|
||||
request_vt_switch_idle (gpointer user_data)
|
||||
{
|
||||
handle_request_vt_switch (user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
send_message_to_wl (MetaLauncher *self,
|
||||
void *message,
|
||||
gsize size,
|
||||
GSocketControlMessage *out_cmsg,
|
||||
GSocketControlMessage **in_cmsg,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
GInputVector in_iov = { &reply, sizeof (reply) };
|
||||
GOutputVector out_iov = { message, size };
|
||||
GSocketControlMessage *out_all_cmsg[2];
|
||||
GSocketControlMessage **in_all_cmsg;
|
||||
int flags = 0;
|
||||
int i;
|
||||
|
||||
out_all_cmsg[0] = out_cmsg;
|
||||
out_all_cmsg[1] = NULL;
|
||||
if (g_socket_send_message (self->weston_launch, NULL,
|
||||
&out_iov, 1,
|
||||
out_all_cmsg, -1,
|
||||
flags, NULL, error) != (gssize)size)
|
||||
return FALSE;
|
||||
|
||||
if (g_socket_receive_message (self->weston_launch, NULL,
|
||||
&in_iov, 1,
|
||||
&in_all_cmsg, NULL,
|
||||
&flags, NULL, error) != sizeof (reply))
|
||||
return FALSE;
|
||||
|
||||
while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
|
||||
{
|
||||
/* There were events queued */
|
||||
g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT);
|
||||
|
||||
/* This can never happen, because the only time mutter-launch can queue
|
||||
this event is after confirming a VT switch, and we don't make requests
|
||||
during that time.
|
||||
|
||||
Note that getting this event would be really bad, because we would be
|
||||
in the wrong loop/context.
|
||||
*/
|
||||
g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER);
|
||||
|
||||
switch (reply.header.opcode)
|
||||
{
|
||||
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
|
||||
g_idle_add (request_vt_switch_idle, self);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (g_socket_receive_message (self->weston_launch, NULL,
|
||||
&in_iov, 1,
|
||||
NULL, NULL,
|
||||
&flags, NULL, error) != sizeof (reply))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (reply.ret != 0)
|
||||
{
|
||||
if (reply.ret == -1)
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Got failure from weston-launch");
|
||||
else
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret),
|
||||
"Got failure from weston-launch: %s", strerror (-reply.ret));
|
||||
|
||||
for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
|
||||
g_object_unref (in_all_cmsg[i]);
|
||||
g_free (in_all_cmsg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (in_all_cmsg && in_all_cmsg[0])
|
||||
{
|
||||
for (i = 1; in_all_cmsg[i]; i++)
|
||||
g_object_unref (in_all_cmsg[i]);
|
||||
*in_cmsg = in_all_cmsg[0];
|
||||
}
|
||||
|
||||
g_free (in_all_cmsg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
meta_launcher_open_device (MetaLauncher *self,
|
||||
const char *name,
|
||||
int flags,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_open *message;
|
||||
GSocketControlMessage *cmsg;
|
||||
gboolean ok;
|
||||
gsize size;
|
||||
int *fds, n_fd;
|
||||
int ret;
|
||||
|
||||
size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
|
||||
message = g_malloc (size);
|
||||
message->header.opcode = WESTON_LAUNCHER_OPEN;
|
||||
message->flags = flags;
|
||||
strcpy (message->path, name);
|
||||
message->path[strlen(name)] = 0;
|
||||
|
||||
ok = send_message_to_wl (self, message, size, NULL, &cmsg, error);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
|
||||
|
||||
fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
|
||||
g_assert (n_fd == 1);
|
||||
|
||||
ret = fds[0];
|
||||
g_free (fds);
|
||||
g_object_unref (cmsg);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
g_free (message);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_enter (MetaLauncher *launcher)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_kms_display_queue_modes_reset (cogl_display);
|
||||
|
||||
clutter_evdev_reclaim_devices ();
|
||||
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
/* When we mode-switch back, we need to immediately queue a redraw
|
||||
* in case nothing else queued one for us, and force the cursor to
|
||||
* update. */
|
||||
|
||||
clutter_actor_queue_redraw (compositor->stage);
|
||||
meta_cursor_tracker_force_update (compositor->seat->cursor_tracker);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_leave (MetaLauncher *launcher)
|
||||
{
|
||||
clutter_evdev_release_devices ();
|
||||
}
|
||||
|
||||
static int
|
||||
on_evdev_device_open (const char *path,
|
||||
int flags,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaLauncher *launcher = user_data;
|
||||
|
||||
return meta_launcher_open_device (launcher, path, flags, error);
|
||||
}
|
||||
|
||||
static void
|
||||
on_evdev_device_close (int fd,
|
||||
gpointer user_data)
|
||||
{
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_vt_enter (MetaLauncher *launcher)
|
||||
{
|
||||
g_assert (launcher->vt_switched);
|
||||
|
||||
g_main_loop_quit (launcher->nested_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request_vt_switch (MetaLauncher *launcher)
|
||||
{
|
||||
struct weston_launcher_message message;
|
||||
GError *error;
|
||||
gboolean ok;
|
||||
|
||||
meta_launcher_leave (launcher);
|
||||
|
||||
message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
|
||||
|
||||
error = NULL;
|
||||
ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error);
|
||||
if (!ok) {
|
||||
g_warning ("Failed to acknowledge VT switch: %s", error->message);
|
||||
g_error_free (error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (!launcher->vt_switched);
|
||||
launcher->vt_switched = TRUE;
|
||||
|
||||
/* We can't do anything at this point, because we don't
|
||||
have input devices and we don't have the DRM master,
|
||||
so let's run a nested busy loop until the VT is reentered */
|
||||
g_main_loop_run (launcher->nested_loop);
|
||||
|
||||
g_assert (launcher->vt_switched);
|
||||
launcher->vt_switched = FALSE;
|
||||
|
||||
meta_launcher_enter (launcher);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_socket_readable (GSocket *socket,
|
||||
GIOCondition condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLauncher *launcher = user_data;
|
||||
struct weston_launcher_event event;
|
||||
gssize read;
|
||||
GError *error;
|
||||
|
||||
if ((condition & G_IO_IN) == 0)
|
||||
return TRUE;
|
||||
|
||||
error = NULL;
|
||||
read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
|
||||
if (read < (gssize)sizeof(event))
|
||||
{
|
||||
g_warning ("Error reading from weston-launcher socket: %s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (event.header.opcode)
|
||||
{
|
||||
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
|
||||
handle_request_vt_switch (launcher);
|
||||
break;
|
||||
|
||||
case WESTON_LAUNCHER_SERVER_VT_ENTER:
|
||||
handle_vt_enter (launcher);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
env_get_fd (const char *env)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
value = g_getenv (env);
|
||||
|
||||
if (value == NULL)
|
||||
return -1;
|
||||
else
|
||||
return g_ascii_strtoll (value, NULL, 10);
|
||||
}
|
||||
|
||||
MetaLauncher *
|
||||
meta_launcher_new (void)
|
||||
{
|
||||
MetaLauncher *self = g_slice_new0 (MetaLauncher);
|
||||
int launch_fd;
|
||||
|
||||
launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
|
||||
if (launch_fd < 0)
|
||||
g_error ("Invalid mutter-launch socket");
|
||||
|
||||
self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
|
||||
|
||||
self->nested_context = g_main_context_new ();
|
||||
self->nested_loop = g_main_loop_new (self->nested_context, FALSE);
|
||||
|
||||
self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
|
||||
g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL);
|
||||
g_source_attach (self->outer_source, NULL);
|
||||
g_source_unref (self->outer_source);
|
||||
|
||||
self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
|
||||
g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL);
|
||||
g_source_attach (self->inner_source, self->nested_context);
|
||||
g_source_unref (self->inner_source);
|
||||
|
||||
clutter_evdev_set_device_callbacks (on_evdev_device_open,
|
||||
on_evdev_device_close,
|
||||
self);
|
||||
|
||||
#if defined(CLUTTER_WINDOWING_EGL)
|
||||
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
|
||||
{
|
||||
GError *error = NULL;
|
||||
int fd = meta_launcher_open_device (self, "/dev/dri/card0", O_RDWR, &error);
|
||||
if (error)
|
||||
g_error ("Failed to open /dev/dri/card0: %s", error->message);
|
||||
|
||||
clutter_egl_set_kms_fd (fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
meta_launcher_free (MetaLauncher *launcher)
|
||||
{
|
||||
g_source_destroy (launcher->outer_source);
|
||||
g_source_destroy (launcher->inner_source);
|
||||
|
||||
g_main_loop_unref (launcher->nested_loop);
|
||||
g_main_context_unref (launcher->nested_context);
|
||||
|
||||
g_object_unref (launcher->weston_launch);
|
||||
|
||||
g_slice_free (MetaLauncher, launcher);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_launcher_activate_vt (MetaLauncher *launcher,
|
||||
signed char vt,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_activate_vt message;
|
||||
|
||||
message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
|
||||
message.vt = vt;
|
||||
|
||||
return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -17,19 +17,18 @@
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_LOGIN1_H
|
||||
#define META_LOGIN1_H
|
||||
#ifndef META_WESTON_LAUNCH_H
|
||||
#define META_WESTON_LAUNCH_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "weston-launch.h"
|
||||
|
||||
typedef struct _MetaLogin1 MetaLogin1;
|
||||
typedef struct _MetaLauncher MetaLauncher;
|
||||
|
||||
MetaLogin1 *meta_login1_new (void);
|
||||
void meta_login1_free (MetaLogin1 *self);
|
||||
gboolean meta_login1_activate_session (MetaLogin1 *self,
|
||||
GError **error);
|
||||
gboolean meta_login1_activate_vt (MetaLogin1 *self,
|
||||
int vt,
|
||||
GError **error);
|
||||
MetaLauncher *meta_launcher_new (void);
|
||||
void meta_launcher_free (MetaLauncher *self);
|
||||
|
||||
gboolean meta_launcher_activate_vt (MetaLauncher *self,
|
||||
signed char vt,
|
||||
GError **error);
|
||||
#endif
|
@@ -201,37 +201,6 @@
|
||||
<arg name="app_id" type="string"/>
|
||||
</request>
|
||||
|
||||
<enum name="surface_type">
|
||||
<description summary="surface types">
|
||||
Surface
|
||||
</description>
|
||||
<entry name="normal" value="0" summary="A normal window. This is the default type."/>
|
||||
<entry name="modal_dialog" value="1" summary="A modal dialog."/>
|
||||
</enum>
|
||||
|
||||
<request name="set_surface_type">
|
||||
<description summary="set the surface type">
|
||||
Sets the type of the surface. These are high-level "roles" of
|
||||
surfaces designed to give the compositor more heuristics about
|
||||
how to place and manage the window.
|
||||
</description>
|
||||
<arg name="surface_type" type="uint" summary="a surface type from surface_type"/>
|
||||
</request>
|
||||
|
||||
<request name="show_window_menu">
|
||||
<description summary="show the window menu">
|
||||
Clients implementing client-side decorations might want to show
|
||||
a context menu when right-clicking on the decorations, giving the
|
||||
user a menu that they can use to maximize or minimize the window.
|
||||
|
||||
The seat passed must have either pointer or keyboard focus to pop
|
||||
up the window menu for a surface.
|
||||
</description>
|
||||
|
||||
<arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/>
|
||||
<arg name="serial" type="uint" summary="serial of the event to pop up the window for"/>
|
||||
</request>
|
||||
|
||||
<request name="move">
|
||||
<description summary="start an interactive move">
|
||||
Start a pointer-driven move of the surface.
|
711
src/wayland/weston-launch.c
Normal file
711
src/wayland/weston-launch.c
Normal file
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* Copyright © 2012 Benjamin Franzke
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <error.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <termios.h>
|
||||
#include <linux/vt.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include <systemd/sd-login.h>
|
||||
|
||||
#include "weston-launch.h"
|
||||
|
||||
#define MAX_ARGV_SIZE 256
|
||||
#define DRM_MAJOR 226
|
||||
|
||||
enum vt_state {
|
||||
VT_HAS_VT,
|
||||
VT_PENDING_CONFIRM,
|
||||
VT_NOT_HAVE_VT,
|
||||
};
|
||||
|
||||
struct weston_launch {
|
||||
int tty;
|
||||
int ttynr;
|
||||
int sock[2];
|
||||
struct passwd *pw;
|
||||
|
||||
int signalfd;
|
||||
|
||||
pid_t child;
|
||||
int verbose;
|
||||
|
||||
struct termios terminal_attributes;
|
||||
int kb_mode;
|
||||
enum vt_state vt_state;
|
||||
unsigned vt;
|
||||
|
||||
int drm_fd;
|
||||
};
|
||||
|
||||
union cmsg_data { unsigned char b[4]; int fd; };
|
||||
|
||||
static void quit (struct weston_launch *wl, int status);
|
||||
|
||||
static int
|
||||
weston_launch_allowed(struct weston_launch *wl)
|
||||
{
|
||||
char *session, *seat;
|
||||
int err;
|
||||
|
||||
if (getuid() == 0)
|
||||
return 1;
|
||||
|
||||
err = sd_pid_get_session(getpid(), &session);
|
||||
if (err == 0 && session) {
|
||||
if (sd_session_is_active(session) &&
|
||||
sd_session_get_seat(session, &seat) == 0) {
|
||||
free(seat);
|
||||
free(session);
|
||||
return 1;
|
||||
}
|
||||
free(session);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_launcher_socket(struct weston_launch *wl)
|
||||
{
|
||||
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
|
||||
error(1, errno, "socketpair failed");
|
||||
|
||||
fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_signals(struct weston_launch *wl)
|
||||
{
|
||||
int ret;
|
||||
sigset_t mask;
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
|
||||
ret = sigaction(SIGCHLD, &sa, NULL);
|
||||
assert(ret == 0);
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
|
||||
ret = sigemptyset(&mask);
|
||||
assert(ret == 0);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigaddset(&mask, SIGUSR1);
|
||||
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
assert(ret == 0);
|
||||
|
||||
wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
if (wl->signalfd < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setenv_fd(const char *env, int fd)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
snprintf(buf, sizeof buf, "%d", fd);
|
||||
setenv(env, buf, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
|
||||
reply.ret = -1;
|
||||
|
||||
if (wl->vt_state != VT_PENDING_CONFIRM) {
|
||||
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wl->drm_fd != -1) {
|
||||
int ret;
|
||||
|
||||
ret = drmDropMaster(wl->drm_fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "failed to drop DRM master: %m\n");
|
||||
} else if (wl->verbose) {
|
||||
fprintf(stderr, "dropped DRM master for VT switch\n");
|
||||
}
|
||||
}
|
||||
|
||||
wl->vt_state = VT_NOT_HAVE_VT;
|
||||
ioctl(wl->tty, VT_RELDISP, 1);
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launcher: confirmed VT switch\n");
|
||||
|
||||
reply.ret = 0;
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
struct weston_launcher_activate_vt *message;
|
||||
unsigned vt;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
|
||||
reply.ret = -1;
|
||||
|
||||
if (len != sizeof(*message)) {
|
||||
error(0, 0, "missing value in activate_vt request");
|
||||
goto out;
|
||||
}
|
||||
|
||||
message = msg->msg_iov->iov_base;
|
||||
|
||||
/* Negative values mean that we're activating our own VT */
|
||||
if (message->vt > 0)
|
||||
vt = message->vt;
|
||||
else
|
||||
vt = wl->vt;
|
||||
|
||||
reply.ret = ioctl(wl->tty, VT_ACTIVATE, vt);
|
||||
if (reply.ret < 0)
|
||||
reply.ret = -errno;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret);
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
int fd = -1;
|
||||
char control[CMSG_SPACE(sizeof(fd))];
|
||||
struct cmsghdr *cmsg;
|
||||
struct stat s;
|
||||
struct msghdr nmsg;
|
||||
struct iovec iov;
|
||||
struct weston_launcher_open *message;
|
||||
union cmsg_data *data;
|
||||
int dev_major;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_OPEN;
|
||||
reply.ret = -1;
|
||||
|
||||
message = msg->msg_iov->iov_base;
|
||||
if ((size_t)len < sizeof(*message))
|
||||
goto err0;
|
||||
|
||||
/* Ensure path is null-terminated */
|
||||
((char *) message)[len-1] = '\0';
|
||||
|
||||
if (stat(message->path, &s) < 0) {
|
||||
reply.ret = -errno;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dev_major = major(s.st_rdev);
|
||||
|
||||
if (dev_major != INPUT_MAJOR &&
|
||||
dev_major != DRM_MAJOR) {
|
||||
fprintf(stderr, "Device %s is not an input or DRM device\n",
|
||||
message->path);
|
||||
reply.ret = -EPERM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (dev_major == DRM_MAJOR && wl->drm_fd != -1) {
|
||||
fprintf(stderr, "Already have a DRM device open\n");
|
||||
reply.ret = -EPERM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
fd = open(message->path, message->flags);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Error opening device %s: %m\n",
|
||||
message->path);
|
||||
reply.ret = -errno;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (dev_major == DRM_MAJOR) {
|
||||
wl->drm_fd = fd;
|
||||
}
|
||||
|
||||
err0:
|
||||
memset(&nmsg, 0, sizeof nmsg);
|
||||
nmsg.msg_iov = &iov;
|
||||
nmsg.msg_iovlen = 1;
|
||||
if (fd != -1) {
|
||||
nmsg.msg_control = control;
|
||||
nmsg.msg_controllen = sizeof control;
|
||||
cmsg = CMSG_FIRSTHDR(&nmsg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
data = (union cmsg_data *) CMSG_DATA(cmsg);
|
||||
data->fd = fd;
|
||||
nmsg.msg_controllen = cmsg->cmsg_len;
|
||||
reply.ret = 0;
|
||||
}
|
||||
iov.iov_base = &reply;
|
||||
iov.iov_len = sizeof reply;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n",
|
||||
message->path, reply.ret, fd);
|
||||
do {
|
||||
len = sendmsg(wl->sock[0], &nmsg, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_socket_msg(struct weston_launch *wl)
|
||||
{
|
||||
char control[CMSG_SPACE(sizeof(int))];
|
||||
char buf[BUFSIZ];
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
int ret = -1;
|
||||
ssize_t len;
|
||||
struct weston_launcher_message *message;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = sizeof buf;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = sizeof control;
|
||||
|
||||
do {
|
||||
len = recvmsg(wl->sock[0], &msg, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
if (len < 1)
|
||||
return -1;
|
||||
|
||||
message = (void *) buf;
|
||||
switch (message->opcode) {
|
||||
case WESTON_LAUNCHER_OPEN:
|
||||
ret = handle_open(wl, &msg, len);
|
||||
break;
|
||||
case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
|
||||
ret = handle_confirm_vt_switch(wl, &msg, len);
|
||||
break;
|
||||
case WESTON_LAUNCHER_ACTIVATE_VT:
|
||||
ret = handle_activate_vt(wl, &msg, len);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
tty_reset(struct weston_launch *wl)
|
||||
{
|
||||
struct vt_mode mode = { 0 };
|
||||
|
||||
if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
|
||||
fprintf(stderr, "failed to restore keyboard mode: %m\n");
|
||||
|
||||
if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
|
||||
fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
|
||||
|
||||
if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
|
||||
fprintf(stderr, "could not restore terminal to canonical mode\n");
|
||||
|
||||
mode.mode = VT_AUTO;
|
||||
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
|
||||
fprintf(stderr, "could not reset vt handling\n");
|
||||
}
|
||||
|
||||
static void
|
||||
quit(struct weston_launch *wl, int status)
|
||||
{
|
||||
if (wl->child > 0)
|
||||
kill(wl->child, SIGKILL);
|
||||
|
||||
close(wl->signalfd);
|
||||
close(wl->sock[0]);
|
||||
|
||||
if (wl->drm_fd > 0)
|
||||
close(wl->drm_fd);
|
||||
|
||||
tty_reset(wl);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_vt_switch(struct weston_launch *wl)
|
||||
{
|
||||
struct weston_launcher_event message;
|
||||
ssize_t len;
|
||||
|
||||
if (wl->vt_state == VT_HAS_VT) {
|
||||
wl->vt_state = VT_PENDING_CONFIRM;
|
||||
message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
|
||||
} else if (wl->vt_state == VT_NOT_HAVE_VT) {
|
||||
wl->vt_state = VT_HAS_VT;
|
||||
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
|
||||
|
||||
if (wl->drm_fd != -1) {
|
||||
int ret;
|
||||
|
||||
ret = drmSetMaster(wl->drm_fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "failed to become DRM master: %m\n");
|
||||
/* This is very, very bad, and the compositor will crash soon,
|
||||
but oh well... */
|
||||
} else if (wl->verbose) {
|
||||
fprintf(stderr, "became DRM master after VT switch\n");
|
||||
}
|
||||
}
|
||||
|
||||
message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
message.detail = 0;
|
||||
|
||||
do {
|
||||
len = send(wl->sock[0], &message, sizeof(message), 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
handle_signal(struct weston_launch *wl)
|
||||
{
|
||||
struct signalfd_siginfo sig;
|
||||
int pid, status, ret;
|
||||
|
||||
if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
|
||||
error(0, errno, "reading signalfd failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (sig.ssi_signo) {
|
||||
case SIGCHLD:
|
||||
pid = waitpid(-1, &status, 0);
|
||||
if (pid == wl->child) {
|
||||
wl->child = 0;
|
||||
if (WIFEXITED(status))
|
||||
ret = WEXITSTATUS(status);
|
||||
else if (WIFSIGNALED(status))
|
||||
/*
|
||||
* If weston dies because of signal N, we
|
||||
* return 10+N. This is distinct from
|
||||
* weston-launch dying because of a signal
|
||||
* (128+N).
|
||||
*/
|
||||
ret = 10 + WTERMSIG(status);
|
||||
else
|
||||
ret = 0;
|
||||
quit(wl, ret);
|
||||
}
|
||||
break;
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
if (wl->child)
|
||||
kill(wl->child, sig.ssi_signo);
|
||||
break;
|
||||
case SIGUSR1:
|
||||
return handle_vt_switch(wl);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_tty(struct weston_launch *wl)
|
||||
{
|
||||
struct stat buf;
|
||||
struct termios raw_attributes;
|
||||
struct vt_mode mode = { 0 };
|
||||
char *session;
|
||||
char path[PATH_MAX];
|
||||
int ok;
|
||||
|
||||
ok = sd_pid_get_session(getpid(), &session);
|
||||
if (ok < 0)
|
||||
error(1, -ok, "could not determine current session");
|
||||
|
||||
ok = sd_session_get_vt(session, &wl->vt);
|
||||
if (ok < 0)
|
||||
error(1, -ok, "could not determine current TTY");
|
||||
|
||||
snprintf(path, PATH_MAX, "/dev/tty%u", wl->vt);
|
||||
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
|
||||
|
||||
if (wl->tty < 0)
|
||||
error(1, errno, "failed to open tty");
|
||||
|
||||
if (fstat(wl->tty, &buf) < 0)
|
||||
error(1, errno, "stat %s failed", path);
|
||||
|
||||
if (major(buf.st_rdev) != TTY_MAJOR)
|
||||
error(1, 0, "invalid tty device: %s", path);
|
||||
|
||||
wl->ttynr = minor(buf.st_rdev);
|
||||
|
||||
if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
|
||||
error(1, errno, "could not get terminal attributes");
|
||||
|
||||
/* Ignore control characters and disable echo */
|
||||
raw_attributes = wl->terminal_attributes;
|
||||
cfmakeraw(&raw_attributes);
|
||||
|
||||
/* Fix up line endings to be normal (cfmakeraw hoses them) */
|
||||
raw_attributes.c_oflag |= OPOST | OCRNL;
|
||||
/* Don't generate ttou signals */
|
||||
raw_attributes.c_oflag &= ~TOSTOP;
|
||||
|
||||
if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
|
||||
error(1, errno, "could not put terminal into raw mode");
|
||||
|
||||
ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
|
||||
ok = ioctl(wl->tty, KDSKBMODE, K_OFF);
|
||||
if (ok < 0) {
|
||||
ok = ioctl(wl->tty, KDSKBMODE, K_RAW);
|
||||
if (ok < 0)
|
||||
error(1, errno, "failed to set keyboard mode on tty");
|
||||
}
|
||||
|
||||
ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
|
||||
if (ok < 0)
|
||||
error(1, errno, "failed to set KD_GRAPHICS mode on tty");
|
||||
|
||||
wl->vt_state = VT_HAS_VT;
|
||||
mode.mode = VT_PROCESS;
|
||||
mode.relsig = SIGUSR1;
|
||||
mode.acqsig = SIGUSR1;
|
||||
ok = ioctl(wl->tty, VT_SETMODE, &mode);
|
||||
if (ok < 0)
|
||||
error(1, errno, "failed to take control of vt handling");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
drop_privileges(struct weston_launch *wl)
|
||||
{
|
||||
if (setgid(wl->pw->pw_gid) < 0 ||
|
||||
#ifdef HAVE_INITGROUPS
|
||||
initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
|
||||
#endif
|
||||
setuid(wl->pw->pw_uid) < 0)
|
||||
error(1, errno, "dropping privileges failed");
|
||||
}
|
||||
|
||||
static void
|
||||
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
|
||||
{
|
||||
char command[PATH_MAX];
|
||||
char *child_argv[MAX_ARGV_SIZE];
|
||||
sigset_t mask;
|
||||
int i;
|
||||
|
||||
if (wl->verbose)
|
||||
printf("weston-launch: spawned weston with pid: %d\n", getpid());
|
||||
|
||||
drop_privileges(wl);
|
||||
|
||||
setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
|
||||
setenv("LD_LIBRARY_PATH", LIBDIR, 1);
|
||||
unsetenv("DISPLAY");
|
||||
|
||||
/* Do not give our signal mask to the new process. */
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGUSR1);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
|
||||
snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
|
||||
|
||||
child_argv[0] = wl->pw->pw_shell;
|
||||
child_argv[1] = "-l";
|
||||
child_argv[2] = "-c";
|
||||
child_argv[3] = command;
|
||||
for (i = 0; i < argc; ++i)
|
||||
child_argv[4 + i] = argv[i];
|
||||
child_argv[4 + i] = NULL;
|
||||
|
||||
execv(child_argv[0], child_argv);
|
||||
error(1, errno, "exec failed");
|
||||
}
|
||||
|
||||
static void
|
||||
help(const char *name)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
|
||||
fprintf(stderr, " -u, --user Start session as specified username\n");
|
||||
fprintf(stderr, " -v, --verbose Be verbose\n");
|
||||
fprintf(stderr, " -h, --help Display this help message\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct weston_launch wl;
|
||||
int i, c;
|
||||
struct option opts[] = {
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ 0, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
memset(&wl, 0, sizeof wl);
|
||||
wl.drm_fd = -1;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
wl.verbose = 1;
|
||||
break;
|
||||
case 'h':
|
||||
help("mutter-launch");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
|
||||
error(1, E2BIG, "Too many arguments to pass to weston");
|
||||
|
||||
if (optind >= argc)
|
||||
error(1, 0, "Expected program argument");
|
||||
|
||||
wl.pw = getpwuid(getuid());
|
||||
if (wl.pw == NULL)
|
||||
error(1, errno, "failed to get username");
|
||||
|
||||
if (!weston_launch_allowed(&wl))
|
||||
error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
|
||||
|
||||
if (setup_tty(&wl) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (setup_launcher_socket(&wl) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (setup_signals(&wl) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
wl.child = fork();
|
||||
if (wl.child == -1) {
|
||||
error(1, errno, "fork failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (wl.child == 0)
|
||||
launch_compositor(&wl, argc - optind, argv + optind);
|
||||
|
||||
close(wl.sock[1]);
|
||||
|
||||
while (1) {
|
||||
struct pollfd fds[2];
|
||||
int n;
|
||||
|
||||
fds[0].fd = wl.sock[0];
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = wl.signalfd;
|
||||
fds[1].events = POLLIN;
|
||||
|
||||
n = poll(fds, 2, -1);
|
||||
if (n < 0)
|
||||
error(0, errno, "poll failed");
|
||||
if (fds[0].revents & POLLIN)
|
||||
handle_socket_msg(&wl);
|
||||
if (fds[1].revents)
|
||||
handle_signal(&wl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
68
src/wayland/weston-launch.h
Normal file
68
src/wayland/weston-launch.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright © 2012 Benjamin Franzke
|
||||
* 2013 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _WESTON_LAUNCH_H_
|
||||
#define _WESTON_LAUNCH_H_
|
||||
|
||||
enum weston_launcher_message_type {
|
||||
WESTON_LAUNCHER_REQUEST,
|
||||
WESTON_LAUNCHER_EVENT,
|
||||
};
|
||||
|
||||
enum weston_launcher_opcode {
|
||||
WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_ACTIVATE_VT = (2 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (3 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
};
|
||||
|
||||
enum weston_launcher_server_opcode {
|
||||
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT),
|
||||
WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT),
|
||||
};
|
||||
|
||||
struct weston_launcher_message {
|
||||
int opcode;
|
||||
};
|
||||
|
||||
struct weston_launcher_open {
|
||||
struct weston_launcher_message header;
|
||||
int flags;
|
||||
char path[0];
|
||||
};
|
||||
|
||||
struct weston_launcher_activate_vt {
|
||||
struct weston_launcher_message header;
|
||||
signed char vt;
|
||||
};
|
||||
|
||||
struct weston_launcher_reply {
|
||||
struct weston_launcher_message header;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct weston_launcher_event {
|
||||
struct weston_launcher_message header;
|
||||
int detail; /* unused, but makes sure replies and events are serialized the same */
|
||||
};
|
||||
|
||||
#endif
|
@@ -40,6 +40,7 @@
|
||||
#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"
|
||||
@@ -428,9 +429,8 @@ reload_net_wm_user_time_window (MetaWindow *window,
|
||||
/**
|
||||
* set_title_text:
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* Returns: %TRUE if a new title was set.
|
||||
*/
|
||||
@@ -488,15 +488,18 @@ 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,
|
||||
window->using_net_wm_visible_name,
|
||||
priv->using_net_wm_visible_name,
|
||||
title,
|
||||
window->display->atom__NET_WM_VISIBLE_NAME,
|
||||
&new_title);
|
||||
window->using_net_wm_visible_name = modified;
|
||||
priv->using_net_wm_visible_name = modified;
|
||||
|
||||
meta_window_set_title (window, new_title);
|
||||
|
||||
@@ -508,10 +511,13 @@ 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);
|
||||
window->using_net_wm_name = TRUE;
|
||||
priv->using_net_wm_name = TRUE;
|
||||
|
||||
meta_verbose ("Using _NET_WM_NAME for new title of %s: \"%s\"\n",
|
||||
window->desc, window->title);
|
||||
@@ -519,7 +525,7 @@ reload_net_wm_name (MetaWindow *window,
|
||||
else
|
||||
{
|
||||
set_window_title (window, NULL);
|
||||
window->using_net_wm_name = FALSE;
|
||||
priv->using_net_wm_name = FALSE;
|
||||
if (!initial)
|
||||
meta_window_reload_property (window, XA_WM_NAME, FALSE);
|
||||
}
|
||||
@@ -530,7 +536,10 @@ reload_wm_name (MetaWindow *window,
|
||||
MetaPropValue *value,
|
||||
gboolean initial)
|
||||
{
|
||||
if (window->using_net_wm_name)
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaWindowX11Private *priv = window_x11->priv;
|
||||
|
||||
if (priv->using_net_wm_name)
|
||||
{
|
||||
meta_verbose ("Ignoring WM_NAME \"%s\" as _NET_WM_NAME is set\n",
|
||||
value->v.str);
|
||||
@@ -601,71 +610,14 @@ 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,
|
||||
@@ -683,9 +635,9 @@ reload_net_wm_state (MetaWindow *window,
|
||||
window->maximized_horizontally = FALSE;
|
||||
window->maximized_vertically = FALSE;
|
||||
window->fullscreen = FALSE;
|
||||
window->wm_state_modal = FALSE;
|
||||
window->wm_state_skip_taskbar = FALSE;
|
||||
window->wm_state_skip_pager = FALSE;
|
||||
priv->wm_state_modal = FALSE;
|
||||
priv->wm_state_skip_taskbar = FALSE;
|
||||
priv->wm_state_skip_pager = FALSE;
|
||||
window->wm_state_above = FALSE;
|
||||
window->wm_state_below = FALSE;
|
||||
window->wm_state_demands_attention = FALSE;
|
||||
@@ -705,11 +657,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)
|
||||
window->wm_state_modal = TRUE;
|
||||
priv->wm_state_modal = TRUE;
|
||||
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_TASKBAR)
|
||||
window->wm_state_skip_taskbar = TRUE;
|
||||
priv->wm_state_skip_taskbar = TRUE;
|
||||
else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER)
|
||||
window->wm_state_skip_pager = TRUE;
|
||||
priv->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)
|
||||
@@ -1438,10 +1390,9 @@ reload_wm_hints (MetaWindow *window,
|
||||
gboolean initial)
|
||||
{
|
||||
Window old_group_leader;
|
||||
gboolean old_urgent;
|
||||
gboolean urgent;
|
||||
|
||||
old_group_leader = window->xgroup_leader;
|
||||
old_urgent = window->wm_hints_urgent;
|
||||
|
||||
/* Fill in defaults */
|
||||
window->input = TRUE;
|
||||
@@ -1449,7 +1400,7 @@ reload_wm_hints (MetaWindow *window,
|
||||
window->xgroup_leader = None;
|
||||
window->wm_hints_pixmap = None;
|
||||
window->wm_hints_mask = None;
|
||||
window->wm_hints_urgent = FALSE;
|
||||
urgent = FALSE;
|
||||
|
||||
if (value->type != META_PROP_VALUE_INVALID)
|
||||
{
|
||||
@@ -1471,7 +1422,7 @@ reload_wm_hints (MetaWindow *window,
|
||||
window->wm_hints_mask = hints->icon_mask;
|
||||
|
||||
if (hints->flags & XUrgencyHint)
|
||||
window->wm_hints_urgent = TRUE;
|
||||
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,
|
||||
@@ -1488,20 +1439,7 @@ reload_wm_hints (MetaWindow *window,
|
||||
meta_window_group_leader_changed (window);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_window_set_urgent (window, urgent);
|
||||
|
||||
meta_icon_cache_property_changed (&window->icon_cache,
|
||||
window->display,
|
||||
@@ -1733,8 +1671,6 @@ 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 },
|
57
src/x11/window-x11-private.h
Normal file
57
src/x11/window-x11-private.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington, Anders Carlsson
|
||||
* Copyright (C) 2002, 2003 Red Hat, Inc.
|
||||
* Copyright (C) 2003 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 "window-private.h"
|
||||
|
||||
#ifndef META_WINDOW_X11_PRIVATE_H
|
||||
#define META_WINDOW_X11_PRIVATE_H
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _MetaWindowX11Private MetaWindowX11Private;
|
||||
|
||||
struct _MetaWindowX11
|
||||
{
|
||||
MetaWindow parent;
|
||||
|
||||
MetaWindowX11Private *priv;
|
||||
};
|
||||
|
||||
struct _MetaWindowX11Private
|
||||
{
|
||||
/* TRUE if the client forced these on */
|
||||
guint wm_state_skip_taskbar : 1;
|
||||
guint wm_state_skip_pager : 1;
|
||||
|
||||
/* Weird "_NET_WM_STATE_MODAL" flag */
|
||||
guint wm_state_modal : 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 */
|
||||
|
||||
Atom type_atom;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
@@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "window-x11.h"
|
||||
#include "window-x11-private.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -44,9 +45,44 @@
|
||||
#include "window-props.h"
|
||||
#include "xprops.h"
|
||||
|
||||
struct _MetaWindowX11Class
|
||||
{
|
||||
MetaWindowClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaWindowX11, meta_window_x11, META_TYPE_WINDOW)
|
||||
|
||||
static void
|
||||
meta_window_x11_init (MetaWindowX11 *window_x11)
|
||||
{
|
||||
window_x11->priv = meta_window_x11_get_instance_private (window_x11);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_get_default_skip_hints (MetaWindow *window,
|
||||
gboolean *skip_taskbar_out,
|
||||
gboolean *skip_pager_out)
|
||||
{
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
|
||||
|
||||
*skip_taskbar_out = priv->wm_state_skip_taskbar;
|
||||
*skip_pager_out = priv->wm_state_skip_pager;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_x11_class_init (MetaWindowX11Class *klass)
|
||||
{
|
||||
MetaWindowClass *window_class = META_WINDOW_CLASS (klass);
|
||||
|
||||
window_class->get_default_skip_hints = meta_window_x11_get_default_skip_hints;
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_x11_set_net_wm_state (MetaWindow *window)
|
||||
{
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
|
||||
int i;
|
||||
unsigned long data[13];
|
||||
|
||||
@@ -56,7 +92,7 @@ meta_window_x11_set_net_wm_state (MetaWindow *window)
|
||||
data[i] = window->display->atom__NET_WM_STATE_SHADED;
|
||||
++i;
|
||||
}
|
||||
if (window->wm_state_modal)
|
||||
if (priv->wm_state_modal)
|
||||
{
|
||||
data[i] = window->display->atom__NET_WM_STATE_MODAL;
|
||||
++i;
|
||||
@@ -163,11 +199,13 @@ meta_window_x11_set_net_wm_state (MetaWindow *window)
|
||||
void
|
||||
meta_window_x11_update_net_wm_type (MetaWindow *window)
|
||||
{
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
|
||||
int n_atoms;
|
||||
Atom *atoms;
|
||||
int i;
|
||||
|
||||
window->type_atom = None;
|
||||
priv->type_atom = None;
|
||||
n_atoms = 0;
|
||||
atoms = NULL;
|
||||
|
||||
@@ -198,7 +236,7 @@ meta_window_x11_update_net_wm_type (MetaWindow *window)
|
||||
atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DND ||
|
||||
atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
|
||||
{
|
||||
window->type_atom = atoms[i];
|
||||
priv->type_atom = atoms[i];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -212,10 +250,10 @@ meta_window_x11_update_net_wm_type (MetaWindow *window)
|
||||
char *str;
|
||||
|
||||
str = NULL;
|
||||
if (window->type_atom != None)
|
||||
if (priv->type_atom != None)
|
||||
{
|
||||
meta_error_trap_push (window->display);
|
||||
str = XGetAtomName (window->display->xdisplay, window->type_atom);
|
||||
str = XGetAtomName (window->display->xdisplay, priv->type_atom);
|
||||
meta_error_trap_pop (window->display);
|
||||
}
|
||||
|
||||
@@ -261,8 +299,7 @@ meta_window_set_opaque_region (MetaWindow *window,
|
||||
if (region != NULL)
|
||||
window->opaque_region = cairo_region_reference (region);
|
||||
|
||||
if (window->display->compositor)
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -347,8 +384,7 @@ meta_window_set_input_region (MetaWindow *window,
|
||||
if (region != NULL)
|
||||
window->input_region = cairo_region_reference (region);
|
||||
|
||||
if (window->display->compositor)
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -454,8 +490,7 @@ meta_window_set_shape_region (MetaWindow *window,
|
||||
if (region != NULL)
|
||||
window->shape_region = cairo_region_reference (region);
|
||||
|
||||
if (window->display->compositor)
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -694,6 +729,8 @@ gboolean
|
||||
meta_window_x11_client_message (MetaWindow *window,
|
||||
XEvent *event)
|
||||
{
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
|
||||
MetaDisplay *display;
|
||||
|
||||
display = window->display;
|
||||
@@ -868,9 +905,9 @@ meta_window_x11_client_message (MetaWindow *window,
|
||||
if (first == display->atom__NET_WM_STATE_MODAL ||
|
||||
second == display->atom__NET_WM_STATE_MODAL)
|
||||
{
|
||||
window->wm_state_modal =
|
||||
priv->wm_state_modal =
|
||||
(action == _NET_WM_STATE_ADD) ||
|
||||
(action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal);
|
||||
(action == _NET_WM_STATE_TOGGLE && !priv->wm_state_modal);
|
||||
|
||||
meta_window_x11_recalc_window_type (window);
|
||||
meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
|
||||
@@ -879,7 +916,7 @@ meta_window_x11_client_message (MetaWindow *window,
|
||||
if (first == display->atom__NET_WM_STATE_SKIP_PAGER ||
|
||||
second == display->atom__NET_WM_STATE_SKIP_PAGER)
|
||||
{
|
||||
window->wm_state_skip_pager =
|
||||
priv->wm_state_skip_pager =
|
||||
(action == _NET_WM_STATE_ADD) ||
|
||||
(action == _NET_WM_STATE_TOGGLE && !window->skip_pager);
|
||||
|
||||
@@ -890,7 +927,7 @@ meta_window_x11_client_message (MetaWindow *window,
|
||||
if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR ||
|
||||
second == display->atom__NET_WM_STATE_SKIP_TASKBAR)
|
||||
{
|
||||
window->wm_state_skip_taskbar =
|
||||
priv->wm_state_skip_taskbar =
|
||||
(action == _NET_WM_STATE_ADD) ||
|
||||
(action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar);
|
||||
|
||||
@@ -1165,11 +1202,6 @@ meta_window_x11_client_message (MetaWindow *window,
|
||||
|
||||
meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
|
||||
}
|
||||
else if (event->xclient.message_type ==
|
||||
display->atom__GTK_SHOW_WINDOW_MENU)
|
||||
{
|
||||
meta_window_show_menu (window);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1315,7 +1347,7 @@ is_our_xwindow (MetaDisplay *display,
|
||||
if (xwindow == screen->guard_window)
|
||||
return TRUE;
|
||||
|
||||
if (display->compositor && xwindow == XCompositeGetOverlayWindow (display->xdisplay, screen->xroot))
|
||||
if (xwindow == XCompositeGetOverlayWindow (display->xdisplay, screen->xroot))
|
||||
return TRUE;
|
||||
|
||||
/* Any windows created via meta_create_offscreen_window */
|
||||
@@ -1515,40 +1547,42 @@ error:
|
||||
void
|
||||
meta_window_x11_recalc_window_type (MetaWindow *window)
|
||||
{
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
|
||||
MetaWindowType type;
|
||||
|
||||
if (window->type_atom != None)
|
||||
if (priv->type_atom != None)
|
||||
{
|
||||
if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
|
||||
if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
|
||||
type = META_WINDOW_DESKTOP;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK)
|
||||
type = META_WINDOW_DOCK;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||
type = META_WINDOW_TOOLBAR;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU)
|
||||
type = META_WINDOW_MENU;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY)
|
||||
type = META_WINDOW_UTILITY;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
|
||||
type = META_WINDOW_SPLASHSCREEN;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG)
|
||||
type = META_WINDOW_DIALOG;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
|
||||
type = META_WINDOW_NORMAL;
|
||||
/* The below are *typically* override-redirect windows, but the spec does
|
||||
* not disallow using them for managed windows.
|
||||
*/
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
|
||||
type = META_WINDOW_DROPDOWN_MENU;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_POPUP_MENU)
|
||||
type = META_WINDOW_POPUP_MENU;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLTIP)
|
||||
type = META_WINDOW_TOOLTIP;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NOTIFICATION)
|
||||
type = META_WINDOW_NOTIFICATION;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_COMBO)
|
||||
type = META_WINDOW_COMBO;
|
||||
else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND)
|
||||
else if (priv->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DND)
|
||||
type = META_WINDOW_DND;
|
||||
else
|
||||
{
|
||||
@@ -1561,7 +1595,7 @@ meta_window_x11_recalc_window_type (MetaWindow *window)
|
||||
|
||||
meta_error_trap_push (window->display);
|
||||
atom_name = XGetAtomName (window->display->xdisplay,
|
||||
window->type_atom);
|
||||
priv->type_atom);
|
||||
meta_error_trap_pop (window->display);
|
||||
|
||||
meta_warning ("Unrecognized type atom [%s] set for %s \n",
|
||||
@@ -1581,8 +1615,7 @@ meta_window_x11_recalc_window_type (MetaWindow *window)
|
||||
type = META_WINDOW_NORMAL;
|
||||
}
|
||||
|
||||
if (type == META_WINDOW_DIALOG &&
|
||||
window->wm_state_modal)
|
||||
if (type == META_WINDOW_DIALOG && priv->wm_state_modal)
|
||||
type = META_WINDOW_MODAL_DIALOG;
|
||||
|
||||
/* We don't want to allow override-redirect windows to have decorated-window
|
||||
@@ -1622,3 +1655,36 @@ meta_window_x11_recalc_window_type (MetaWindow *window)
|
||||
type, window->desc, type);
|
||||
meta_window_set_type (window, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_window_x11_configure_notify: (skip)
|
||||
* @window: a #MetaWindow
|
||||
* @event: a #XConfigureEvent
|
||||
*
|
||||
* This is used to notify us of an unrequested configuration
|
||||
* (only applicable to override redirect windows)
|
||||
*/
|
||||
void
|
||||
meta_window_x11_configure_notify (MetaWindow *window,
|
||||
XConfigureEvent *event)
|
||||
{
|
||||
g_assert (window->override_redirect);
|
||||
g_assert (window->frame == NULL);
|
||||
|
||||
window->rect.x = event->x;
|
||||
window->rect.y = event->y;
|
||||
window->rect.width = event->width;
|
||||
window->rect.height = event->height;
|
||||
meta_window_update_monitor (window);
|
||||
|
||||
/* Whether an override-redirect window is considered fullscreen depends
|
||||
* on its geometry.
|
||||
*/
|
||||
if (window->override_redirect)
|
||||
meta_screen_queue_check_fullscreen (window->screen);
|
||||
|
||||
if (!event->override_redirect && !event->send_event)
|
||||
meta_warning ("Unhandled change of windows override redirect status\n");
|
||||
|
||||
meta_compositor_sync_window_geometry (window->display->compositor, window, FALSE);
|
||||
}
|
@@ -26,6 +26,20 @@
|
||||
#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);
|
||||
|
||||
@@ -44,4 +58,7 @@ 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
|
@@ -1,7 +0,0 @@
|
||||
# completely hacked-up makefile, proceed at your own risk, etc
|
||||
|
||||
default:
|
||||
@echo "Try 'make tp' or 'make glib'"
|
||||
|
||||
tp: tokentest.c
|
||||
gcc `pkg-config --cflags --libs glib-2.0 gdk-2.0 atk` -DMUTTER_DATADIR=\"/usr/share/mutter\" -I../.. -I../../src -I../../src/include tokentest.c ../../src/ui/theme.c ../../src/ui/gradient.c -o tp
|
@@ -1,19 +0,0 @@
|
||||
Tokeniser test
|
||||
==============
|
||||
This directory contains a set of tools for checking the behaviour
|
||||
of the tokeniser for Metacity theme files.
|
||||
|
||||
tokentest.ini contains a list of all expressions retrieved from
|
||||
all theme files on art.gnome.org, and mappings to what the tokenising
|
||||
should be, in a separate representation. get-tokens.py produces the
|
||||
template version of this; it will produce a file with no expected
|
||||
values.
|
||||
|
||||
tokentest.c will either check that a tokeniser behaves according to
|
||||
tokentest.ini, or, if it finds a file, is empty it will print the
|
||||
values that the tokeniser it's using is producing.
|
||||
|
||||
The makefile is a hacky attempt at letting you compile either against
|
||||
Metacity's existing tokeniser or one which uses GLib's "scanner".
|
||||
|
||||
This code may or may not eventually end up in the automated test suite.
|
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (C) 2008 Thomas Thurman
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
|
||||
import os
|
||||
import xml.sax
|
||||
|
||||
standard = ['x', 'y', 'width', 'height']
|
||||
|
||||
expressions = {
|
||||
'line': ['x1', 'x2', 'y1', 'y2'],
|
||||
'rectangle': standard,
|
||||
'arc': standard,
|
||||
'clip': standard,
|
||||
'gradient': standard,
|
||||
'image': standard,
|
||||
'gtk_arrow': standard,
|
||||
'gtk_box': standard,
|
||||
'gtk_vline': standard,
|
||||
'icon': standard,
|
||||
'title': standard,
|
||||
'include': standard,
|
||||
'tile': ['x', 'y', 'width', 'height',
|
||||
'tile_xoffset', 'tile_yoffset',
|
||||
'tile_width', 'tile_height'],
|
||||
}
|
||||
|
||||
all_themes = '../../../all-themes/'
|
||||
|
||||
result = {}
|
||||
|
||||
class themeparser:
|
||||
def __init__(self, name):
|
||||
self.filename = name
|
||||
|
||||
def processingInstruction(self):
|
||||
pass
|
||||
|
||||
def characters(self, what):
|
||||
pass
|
||||
|
||||
def setDocumentLocator(self, where):
|
||||
pass
|
||||
|
||||
def startDocument(self):
|
||||
pass
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if expressions.has_key(name):
|
||||
for attr in expressions[name]:
|
||||
if attrs.has_key(attr):
|
||||
expression = attrs[attr]
|
||||
if not result.has_key(expression): result[expression] = {}
|
||||
result[expression][self.filename] = 1
|
||||
|
||||
def endElement(self, name):
|
||||
pass # print "end element"
|
||||
|
||||
def endDocument(self):
|
||||
pass
|
||||
|
||||
def maybe_parse(themename, filename):
|
||||
if os.access(all_themes+filename, os.F_OK):
|
||||
parser = themeparser(themename)
|
||||
xml.sax.parse(all_themes+filename, parser)
|
||||
|
||||
for theme in os.listdir(all_themes):
|
||||
maybe_parse(theme, theme+'/metacity-1/metacity-theme-1.xml')
|
||||
maybe_parse(theme, theme+'/metacity-theme-1.xml')
|
||||
|
||||
print '[tokentest0]'
|
||||
|
||||
for expr in sorted(result.keys()):
|
||||
print "# %s" % (', '.join(sorted(result[expr])))
|
||||
print "%s=REQ" % (expr)
|
||||
print
|
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* tokentest.c - test for Metacity's tokeniser
|
||||
*
|
||||
* Copyright (C) 2008 Thomas Thurman
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* Still under heavy development. */
|
||||
/* Especially: FIXME: GErrors need checking! */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <glib/gerror.h>
|
||||
#include <gtk/gtkobject.h>
|
||||
#include <gtk/gtkicontheme.h>
|
||||
#include <ui/theme.h>
|
||||
#include <util.h>
|
||||
|
||||
#define TOKENTEST_GROUP "tokentest0"
|
||||
|
||||
/************************/
|
||||
/* Dummy functions which are just here to keep the linker happy */
|
||||
|
||||
MetaTheme* meta_theme_load (const char *theme_name,
|
||||
GError **err) {
|
||||
/* dummy */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_bug(const char *format, ...)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
void
|
||||
meta_warning(const char *format, ...)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
GType
|
||||
gtk_widget_get_type (void)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
GType
|
||||
gtk_object_get_type (void)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
void gtk_paint_arrow (GtkStyle *style,
|
||||
GdkWindow *window,
|
||||
GtkStateType state_type,
|
||||
GtkShadowType shadow_type,
|
||||
GdkRectangle *area,
|
||||
GtkWidget *widget,
|
||||
const gchar *detail,
|
||||
GtkArrowType arrow_type,
|
||||
gboolean fill,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
void gtk_paint_vline (GtkStyle *style,
|
||||
GdkWindow *window,
|
||||
GtkStateType state_type,
|
||||
GdkRectangle *area,
|
||||
GtkWidget *widget,
|
||||
const gchar *detail,
|
||||
gint y1_,
|
||||
gint y2_,
|
||||
gint x)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
void gtk_paint_box (GtkStyle *style,
|
||||
GdkWindow *window,
|
||||
GtkStateType state_type,
|
||||
GtkShadowType shadow_type,
|
||||
GdkRectangle *area,
|
||||
GtkWidget *widget,
|
||||
const gchar *detail,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
GtkIconTheme *gtk_icon_theme_get_default (void)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
GdkPixbuf * gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
|
||||
const gchar *icon_name,
|
||||
gint size,
|
||||
GtkIconLookupFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
MetaRectangle meta_rect (int x, int y, int width, int height)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
void
|
||||
meta_topic_real (MetaDebugTopic topic,
|
||||
const char *format,
|
||||
...)
|
||||
{
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
|
||||
/*********************************/
|
||||
|
||||
GString *draw_spec_to_string(MetaDrawSpec *spec)
|
||||
{
|
||||
GString *result;
|
||||
int i;
|
||||
|
||||
if (spec == NULL)
|
||||
return g_string_new ("NONE");
|
||||
|
||||
result = g_string_new ("");
|
||||
|
||||
if (spec->constant)
|
||||
{
|
||||
g_string_append_printf (result, "{%d==}", spec->value);
|
||||
}
|
||||
|
||||
for (i=0; i<spec->n_tokens; i++)
|
||||
{
|
||||
PosToken t = spec->tokens[i];
|
||||
|
||||
switch (t.type)
|
||||
{
|
||||
case POS_TOKEN_INT:
|
||||
g_string_append_printf (result, "(int %d)", t.d.i.val);
|
||||
break;
|
||||
|
||||
case POS_TOKEN_DOUBLE:
|
||||
g_string_append_printf (result, "(double %g)", t.d.d.val);
|
||||
break;
|
||||
|
||||
case POS_TOKEN_OPERATOR:
|
||||
|
||||
switch (t.d.o.op) {
|
||||
case POS_OP_NONE:
|
||||
g_string_append (result, "(no-op)");
|
||||
break;
|
||||
|
||||
case POS_OP_ADD:
|
||||
g_string_append (result, "(add)");
|
||||
break;
|
||||
|
||||
case POS_OP_SUBTRACT:
|
||||
g_string_append (result, "(subtract)");
|
||||
break;
|
||||
|
||||
case POS_OP_MULTIPLY:
|
||||
g_string_append (result, "(multiply)");
|
||||
break;
|
||||
|
||||
case POS_OP_DIVIDE:
|
||||
g_string_append (result, "(divide)");
|
||||
break;
|
||||
|
||||
case POS_OP_MOD:
|
||||
g_string_append (result, "(mod)");
|
||||
break;
|
||||
|
||||
case POS_OP_MAX:
|
||||
g_string_append (result, "(max)");
|
||||
break;
|
||||
|
||||
case POS_OP_MIN:
|
||||
g_string_append (result, "(min)");
|
||||
break;
|
||||
|
||||
default:
|
||||
g_string_append_printf (result, "(op %d)", t.d.o.op);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case POS_TOKEN_VARIABLE:
|
||||
g_string_append_printf (result, "(str %s)", t.d.v.name);
|
||||
break;
|
||||
|
||||
case POS_TOKEN_OPEN_PAREN:
|
||||
g_string_append (result, "( ");
|
||||
break;
|
||||
|
||||
case POS_TOKEN_CLOSE_PAREN:
|
||||
g_string_append (result, " )");
|
||||
break;
|
||||
|
||||
default:
|
||||
g_string_append_printf (result, "(strange %d)", t.type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GKeyFile *keys;
|
||||
|
||||
void
|
||||
load_keys ()
|
||||
{
|
||||
GError* err = NULL;
|
||||
gchar** keys_of_file;
|
||||
gchar** cursor;
|
||||
gboolean ever_printed_header = FALSE;
|
||||
gint passes = 0, fails = 0;
|
||||
|
||||
keys = g_key_file_new ();
|
||||
|
||||
g_key_file_load_from_file (keys,
|
||||
"tokentest.ini",
|
||||
G_KEY_FILE_KEEP_COMMENTS,
|
||||
&err);
|
||||
|
||||
keys_of_file = g_key_file_get_keys (keys,
|
||||
TOKENTEST_GROUP,
|
||||
NULL,
|
||||
&err);
|
||||
|
||||
cursor = keys_of_file;
|
||||
|
||||
while (*cursor)
|
||||
{
|
||||
gchar *desideratum = g_key_file_get_value (keys,
|
||||
TOKENTEST_GROUP,
|
||||
*cursor,
|
||||
&err);
|
||||
MetaTheme *dummy = meta_theme_new ();
|
||||
MetaDrawSpec *spec;
|
||||
GString *str;
|
||||
|
||||
spec = meta_draw_spec_new (dummy, *cursor, &err);
|
||||
|
||||
str = draw_spec_to_string (spec);
|
||||
|
||||
if (strcmp ("REQ", desideratum)==0) {
|
||||
gchar *comment = g_key_file_get_comment (keys, TOKENTEST_GROUP, *cursor, &err);
|
||||
|
||||
if (!ever_printed_header) {
|
||||
g_print ("[%s]\n", TOKENTEST_GROUP);
|
||||
ever_printed_header = TRUE;
|
||||
}
|
||||
|
||||
g_print ("\n#%s%s=%s\n", comment? comment: "", *cursor, str->str);
|
||||
g_free (comment);
|
||||
} else if (strcmp (str->str, desideratum)==0) {
|
||||
g_print("PASS: %s\n", *cursor);
|
||||
passes++;
|
||||
} else {
|
||||
g_warning ("FAIL: %s, wanted %s, got %s\n",
|
||||
*cursor, desideratum, str->str);
|
||||
fails++;
|
||||
}
|
||||
|
||||
meta_theme_free (dummy);
|
||||
g_string_free (str, TRUE);
|
||||
g_free (desideratum);
|
||||
|
||||
cursor++;
|
||||
}
|
||||
|
||||
g_strfreev (keys_of_file);
|
||||
|
||||
g_print("\n# Passes: %d. Fails: %d.\n", passes, fails);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
load_keys ();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user