Compare commits

..

81 Commits

Author SHA1 Message Date
Giovanni Campagna
7f07b4a0fc Add keybindings for switching VTs
Once mutter is started from weston-launch on its own VT, there is
no way to change VT again (for example to actually start an application),
because the keyboard is put in raw mode.
So introduce some keybindings mimicking the standard X ones (Ctrl+Alt+Fn)
that switch the VT manually when activated.

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 11:12:44 +02:00
Giovanni Campagna
c9a9c5fe79 wayland: add TTY and DRM master management
Now that we have a setuid launcher binary, we can make use of
using a private protocol through the socket we're passed at startup.

We also use the new hook in clutter-evdev to ask mutter-launch for
the FDs of the input devices we need, and we emulate the old X
DRM lock with a nested GMainContext without sources.

In the future, mutter-launch will be replaced with the new logind
API currently in development.

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 11:12:44 +02:00
Giovanni Campagna
04aff06876 mutter-launch: augment with VT and TTY handling
Set the TTY mode appropriately at startup, and clean it up
when the compositor exits. Also, take control of VT switching,
and make sure that the compositor calls drmDropMaster when switched
away.
In the future, we the kernel implements the mute evdev ioctl,
we'll also make sure that input devices are appropriately released.

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 11:12:44 +02:00
Giovanni Campagna
1cb5284113 mutter-launch: use systemd to obtain the TTY
Using the command line or an environment variable is dangerous,
as those can be spoofed to gain access to other sessions.

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 11:12:43 +02:00
Giovanni Campagna
b1e758b341 mutter-launch: make sure that the spawned binaries sees the right libraries
Being a setuid binary, our LD_LIBRARY_PATH is cleared by glibc at
startup, but we need the spawned binary to see it, otherwise
jhbuild doesn't work, so hardcode it using the configured libdir.

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 11:12:30 +02:00
Giovanni Campagna
96753bb703 mutter-launch: simplify by removing features we don't need
Remove the ability to launch as a different user, which we don't
need because we're spawned by gdm or by the user manually on the
command line.
At the same time, require an active local session, and remove
the ability to run from anywhere by being in the right user group
(which automatically gives you root-like privileges)

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 11:11:10 +02:00
Giovanni Campagna
33b06f97e3 wayland: import weston-launch setuid launcher
To run mutter as a display server, one needs to acquire and
release the DRM master, which is only possible for root, so
we take advantage of weston-launch, a small setuid helper binary
written for the weston project. We import our own slightly
modified copy of it, because weston-launch only launches weston,
for security reasons.

https://bugzilla.gnome.org/show_bug.cgi?id=705861
2013-08-28 10:43:37 +02:00
Jasper St. Pierre
c9830c13b4 screen: Remove unused variable 2013-08-27 08:56:06 -04:00
Giovanni Campagna
9a4783e364 Integrate the monitor manager with wayland
Use the right backend when running as a wayland compositor,
export the data to wayland clients, and use it to keep the stage
appropriately sized.
2013-08-27 10:09:39 +02:00
Giovanni Campagna
aa15c09d54 Merge tag 'xrandr_branch_point' into wayland-kms-base
Conflicts:
	src/Makefile.am
	src/core/display.c
	src/core/screen-private.h
	src/core/screen.c
2013-08-27 10:07:39 +02:00
Giovanni Campagna
62d908be42 MonitorManager: return the new backlight after changing
Modify the interface of ChangeBacklight to return the new value,
to account for rounding to HW limits.

https://bugzilla.gnome.org/show_bug.cgi?id=706729
2013-08-27 09:58:50 +02:00
Jasper St. Pierre
6526e9882b idle-monitor: Fix a warning when a callback removes the user active watch
The user active watch is a one-fire watch, but it is valid in the API
for the callback to explicitly remove the watch itself. In that case,
the watch will be invalid after the user removes it, and the memory
potentially freed. So make sure to not dereference the watch after
the callback is called.

https://bugzilla.gnome.org/show_bug.cgi?id=706825
2013-08-27 09:57:06 +02:00
Tim Lunn
ab72352c47 background: don't save pixbuf in user data
https://bugzilla.gnome.org/show_bug.cgi?id=706777
2013-08-27 09:57:06 +02:00
Giovanni Campagna
f09b9573f0 window: ignore skip-taskbar hint on parentless dialogs
Dialogs that don't have a parent should not be skip-taskbar,
otherwise they get lost and there is no way to recover them
(because they're not autoraised when activating the parent),
but toolkits and applications set the hint anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=673399
2013-08-27 09:57:06 +02:00
Florian Müllner
3d3ae40f79 Bump version to 3.9.90
gnome-shell requires mutter and mutter-wayland at the same version
to build. Also update NEWS, cherry-picked from master.
2013-08-27 09:51:56 +02:00
Giovanni Campagna
ea3d2b4759 wayland: make parallel installable with regular mutter
Modify all visible instances of mutter with mutter-wayland
(libraries, folders, pkgconfig, etc.), so that the wayland
branch can be installed alongside the usual X11 mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=705497
2013-08-26 15:00:29 +02:00
Giovanni Campagna
542a0886cf Remove files no one cares about anymore
mutter-plugins.pc has been replaced by libmutter.pc, and the
wm properties in the control center are long gone.

https://bugzilla.gnome.org/show_bug.cgi?id=705497
2013-08-26 15:00:29 +02:00
Giovanni Campagna
bd3d5df9ce Remove HAVE_WAYLAND ifdefs
Wayland support is always enabled now.

https://bugzilla.gnome.org/show_bug.cgi?id=705497
2013-08-26 15:00:29 +02:00
Giovanni Campagna
91cdfab495 build: make wayland support unconditional
In the wayland branch of mutter, we want to build a wayland version
of the mutter libraries, and that's much easier if we just build
wayland support unconditionally.
The define is kept to avoid a huge diff, but should be removed
in a later patch.
Also, wayland support can still be disable at runtime, by
launching mutter without the --nested switch.

https://bugzilla.gnome.org/show_bug.cgi?id=705497
2013-08-26 15:00:29 +02:00
Giovanni Campagna
1617323dca MetaShapedTexture: don't include private headers in public ones
Private headers are not installed, so they can't be referenced
from public ones.

https://bugzilla.gnome.org/show_bug.cgi?id=705497
2013-08-26 15:00:29 +02:00
Florian Müllner
bbf9358eba window: Fix a compiler warning 2013-08-23 23:09:58 -04:00
Jasper St. Pierre
9682a2aea4 window-group: Fix compiler warning 2013-08-23 22:11:37 -04:00
Jasper St. Pierre
c9fbb51775 wayland: Fix build when building without Wayland 2013-08-23 22:05:11 -04:00
Jasper St. Pierre
aa6d887214 wayland-private: Ignore deprecations around legacy_buffer
yes, it's deprecated, that's why it's marked legacy. now shush.
2013-08-23 22:00:52 -04:00
Jasper St. Pierre
13312527de Update .gitignore 2013-08-23 18:23:33 -04:00
Giovanni Campagna
9bd366f2a6 MonitorXrandr: skip CRTC reconfigurations that have no effect
If we're attempting to reconfigure the CRTCs to the same parameter,
skip the X call, as in some drivers a modeset can take time and
cause flicker.

https://bugzilla.gnome.org/show_bug.cgi?id=706672
2013-08-23 18:06:02 +02:00
Colin Guthrie
5de346bfef MonitorXrandr: Fix segv when accessing possible_clones
This code requires a double pass and the segv happens later
when trying to iterate over the array.

https://bugzilla.gnome.org/show_bug.cgi?id=706598
2013-08-23 16:40:43 +02:00
Giovanni Campagna
2af20b77b6 MonitorXrandr: fix reading the current DPMS level
Add missing break statements, to avoid falling always through
to the invalid case.

https://bugzilla.gnome.org/show_bug.cgi?id=706582
2013-08-23 16:40:43 +02:00
Giovanni Campagna
9affbf10a6 MetaIdleMonitor: add wayland support
Keep a timer source that we reset when we capture an event in
MetaWayland, and fire watches accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=706005
2013-08-23 16:34:02 +02:00
Giovanni Campagna
c0acf3ae6d MetaIdleMonitor: add a DBus interface for the idle monitor
To allow other clients (gnome-session, gnome-settings-daemon)
to monitor user activity, introduce a DBus interface for the
idle monitor inside mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=706005
2013-08-23 16:34:02 +02:00
Giovanni Campagna
2c1b20e15f Add a new helper for tracking user idle activity
When running as a wayland compositor, we can't use the xserver's
IDLETIME, because that's updated only in response to X events.
But we have all the events ourselves, so we can just run the timer
in process.

https://bugzilla.gnome.org/show_bug.cgi?id=706005
2013-08-23 16:34:02 +02:00
Jasper St. Pierre
77290b6736 Update .gitignore 2013-08-20 17:04:43 -04:00
Giovanni Campagna
876f81db12 compositor: fix focusing the stage window
We can't use the X11 stage window, if clutter is not using the X11
backend (and even if it was, it would be bogus when the xwayland
server is not the one clutter is talking to). Instead, we introduce
the concept of "focus type", which we use to differentiate the
various meanings of None in the focus_xwindow field.

https://bugzilla.gnome.org/show_bug.cgi?id=706364
2013-08-20 14:41:24 +02:00
Giovanni Campagna
75f3ae14b5 MetaPlugin: simplify the modal API
Remove grab window and cursor from the API, and just grab always
on the stage window with no cursor.
This is mainly to remove the X11 usage in the public API, in preparation
for implementing this in wayland.

https://bugzilla.gnome.org/show_bug.cgi?id=705917
2013-08-20 14:25:49 +02:00
Giovanni Campagna
d26f248b0f wayland: fix a compiler warning
Implicit declaration of memset

https://bugzilla.gnome.org/show_bug.cgi?id=706363
2013-08-20 14:13:49 +02:00
Giovanni Campagna
eeb3dfc991 MonitorManager: emit a DBus signal when we change the display configuration
Using out-of-band notifications from the wayland protocol or from
X is racy, in that the client could ask for the new resources before
we have them.
Instead, with a signal, we are sure that when the client asks for
it, it will get the right values.

https://bugzilla.gnome.org/show_bug.cgi?id=706382
2013-08-20 14:08:50 +02:00
Giovanni Campagna
e66db2eab3 MonitorManager: extend the API with physical sizes
These will be needed in the new display panel designs to show
the diagonal length and physical aspect ratio.

https://bugzilla.gnome.org/show_bug.cgi?id=706322
2013-08-20 14:08:50 +02:00
Giovanni Campagna
2ae7454f36 Add MetaCursorTracker, a new helper for tracking the cursor sprite
Under X, we need to use XFixes to watch the cursor changing, while
on wayland, we're in charge of setting and painting the cursor.
MetaCursorTracker provides the abstraction layer for gnome-shell,
which can thus drop ShellXFixesCursor. In the future, it may grow
the ability to watch for pointer position too, especially if
CursorEvents are added to the next version of XInput2, and thus
it would also replace the PointerWatcher we use for gnome-shell's
magnifier.

https://bugzilla.gnome.org/show_bug.cgi?id=705911
2013-08-19 16:09:53 +02:00
Giovanni Campagna
4fd3c63da9 ui: restrict gtk to only use the x11 backend
We use GTK as a way to get the X11 connection for our internal
use, so we need it to keep using X.

https://bugzilla.gnome.org/show_bug.cgi?id=706303
2013-08-19 15:42:37 +02:00
Giovanni Campagna
909a6607c5 MonitorXrandr: try harder to get decent product/serial IDs
If the EDID does not include free-form product name and serial
number, use the numeric IDs instead, like gnome-desktop did.

https://bugzilla.gnome.org/show_bug.cgi?id=706233
2013-08-19 09:45:31 +02:00
Piotr Drąg
1bde397edf Updated POTFILES.in 2013-08-18 22:03:23 +02:00
Giovanni Campagna
015c05fbf6 MonitorXrandr: fix setting gamma ramps
The value passed to XRRCrtcSetGamma must be allocated with
XRRAllocGamma (because it relies on the locations of green and blue),
otherwise garbage is sent on the wire.

https://bugzilla.gnome.org/show_bug.cgi?id=706231
2013-08-18 12:11:42 +02:00
Giovanni Campagna
8ad5ccd2f8 MonitorConfig: switch to the real configuration file
Forgot to do before pushing...
2013-08-18 01:10:00 +02:00
Colin Walters
115cc870c7 build: Fix srcdir != builddir 2013-08-17 19:05:50 -04:00
Giovanni Campagna
3112794d83 MonitorXrandr: update the internal data structures after applying
We were relying on the XRandR events from the X server to update
the configuration, but we were calling meta_monitor_config_update_current()
immediately after, so the MonitorConfig would be updated with the
old configuration (and we would save that to disk!)

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:48:31 +02:00
Giovanni Campagna
3528b067d0 MonitorXrandr: follow the right order in applying the new configuration
First disable CRTCs that should be off in the new configuration,
then resize the framebuffer, then enable the new CRTCs.
If we don't do that, and we're making the screen smaller, X complains
with a BadMatch.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
0986b660be MonitorXrandr: resize the framebuffer prior to setting the CRTC configuration
Otherwise X11 will trim the new configuration and disable outputs
outside the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
3bb5086173 Monitor: restore correct display name handling
Now that we have the right values from the EDID, we can load
the PNP database and find the proper vendor name, to show in
the control center UI.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
69467842ab MonitorXrandr: implement correct EDID parsing
To provide valid values for the vendor, product and serial fields
we need to read the EDID and parse it.
Parser kindly provided by gnome-desktop.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
57077435ed MonitorManager: add EDID properties to the output DBus description
Add "edid-file", if we have one (in the KMS case, where we can point
people to the right sysfs file), or "edid" with inline data.
These are needed by colord to build the default ICC profile for
uncalibrated displays.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
46de0ed462 MonitorManager: split the XRandR parts in a subclass
Instead of keeping a forest of if backend else ..., use a subclass
and virtual functions to discriminate between XRandR and the
dummy backend (which lives in the parent class togheter with the
common code)

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
5086626805 MetaPlugin: add a UI hook for confirming display changes
We want to show a dialog when a display change happens from the
control center. To do so, add a new vfunc to MetaPlugin and
call it when a configuration change is requested via DBus.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
bbbcd8c631 MonitorConfig: handle changes in the laptop lid
This way we don't need to track the current and previous
configuration in gnome-settings-daemon, when we already do so
in mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
3b61b85f2c MonitorManager: add gamma support
Add GetCrtcGamma() and SetCrtcGamma(), that wrap the similarly
named XRandR API. These are used by GnomeRR inside the color
plugin of the control center (and may go away if the color
plugin decides to do something different under wayland)

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
cd20f1bc0b MonitorManager: ignore configuration changes that disable all outputs
If we compute a screen size of 0 in either direction, we crash
later on, as it is invalid for clutter, cogl and X.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
8b52782ed4 MonitorManager: add support for backlight
GnomeRR needs that too.
The backlight is exported as a normalized 0-100 value, or -1 if not
supported. Clamping to HW limits is handled by the backend.
Changing backlight uses a different method call, to avoid recomputing
the full display configuration every time the user presses the
backlight keys.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:53 +02:00
Giovanni Campagna
849050be95 MonitorManager: further extend the dummy backend
The default configuration is extended, which is only possible
if there are as many CRTCs as outputs, so make sure that's true.

Also, add more and bigger modes, so that different sizes will
be chosen for the three outputs.
A nice side effect of this is that with a real 1920x1080 + 1600x900
layout, if you disable the VGA you get a stage that matches the
screen size, which triggers the legacy fullscreen path in the
outside mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:47:52 +02:00
Giovanni Campagna
5c27a91684 MonitorManager: store the presentation mode bit in XRandR
Use a private output property to store if the output is in
presentation mode or not, so that this information is not lost
after the configuration read back from the server.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:34:16 +02:00
Giovanni Campagna
764c472edb MonitorConfig: add support for default configurations
Activate the presentation bit on new hotplugged monitors, while
making a fully extended setup when running for the first time.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:34:16 +02:00
Giovanni Campagna
d0529b7482 MonitorConfig: add CRTC assignment
Ripped off libgnome-desktop, trimming the parts that checked
that the configuration was plausible, as that should be done
in gnome-control-center before asking mutter for a change.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:34:15 +02:00
Giovanni Campagna
8f4621240a MonitorManager: add support for persistent monitor configurations
Add a new object, MetaMonitorConfig, that takes care of converting
between the logical configurations stored in monitors.xml and
the HW resources exposed by MonitorManager.
This commit includes loading and saving of configurations, but
still missing is the actual CRTC assignments and a default
configuration when none is found in the file.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:33:37 +02:00
Giovanni Campagna
e039add240 MonitorManager: add support for DPMS levels
To the XRandR and dummy backend (and as usual the dummy backend
has no effect)

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:33:37 +02:00
Giovanni Campagna
dbd8d4d598 MonitorManager: inherit directly from DisplayConfig instead of handling signals
This way we can handle properties too.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:33:37 +02:00
Giovanni Campagna
522542c486 MonitorManager: fix handling of output transform
Read the current transform from XRandR, and expose the transforms
that are really supported on the bus.
The dummy backend now advertises all transforms, since it doesn't
actually apply them.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:33:35 +02:00
Giovanni Campagna
fc67c707e4 default plugin: add a random color background on each monitor
Instead of a full white background, make one with a random color.
This way the different "monitors" are visible and it's easier
to debug the DBus API.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:32:44 +02:00
Giovanni Campagna
c354e7e81b DisplayConfig: make the dummy backend writable
Add a number of dummy outputs and modes to the dummy backend,
and implement the writing bits.
The only visible effect is that you can change the screen size,
which resizes the output window.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:32:43 +02:00
Giovanni Campagna
bf40409d97 Reverse handling of XRandR events between Screen and MonitorManager
Now MonitorManager does its own handling of XRandR events, which
means we no longer handle ConfigureNotify on the root window.
MetaScreen reacts to MonitorManager::monitor-changed and updates
its internal state, including the new size.

This paves the way for doing display configuration using only
the dummy backend, which would allow testing wl_output interfaces.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:31:10 +02:00
Giovanni Campagna
57d083730e DisplayConfig: add the write side of the API
Implement ApplyConfiguration in terms of XRandR calls.
Error checking is done before actually committing the configuration.

If mutter is using one of the other monitor config backends, an
error is reported and nothing happens.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:31:09 +02:00
Giovanni Campagna
dc242e46c2 Extend the DBus XRandR protocol to expose cloning restriction
Turns out that even if two outputs say that they can be controlled
by a given CRTC, you can't configure them in the same CRTC unless
they are marked as "possible clones" one of the other.
This can further restrict the configuration options, so we need
to expose this limitation in the DBus API.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:22:54 +02:00
Giovanni Campagna
7e1d1003c9 Add the write side of the DBus protocol too
This is just in the documentation for now, to attract wider feedback
before we start looking at how to implement this for real.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:22:54 +02:00
Giovanni Campagna
3bb33d384f Introduce a new DBus interface for display configuration
This new interface will be used by the control center and possibly
the settings daemon to configure the screens. It is designed to
resemble a simplified XRandR, while still exposing all the quirks
of the hardware, so that the panel can limit the user choices
appropriately.

To do so, MetaMonitorMode needs to track CRTCs, outputs and modes,
so the low level objects have been decoupled from the high-level
MetaMonitorInfo, which is used by core and API and offers a simplified
view of HW, that hides away the details of what is cloned and how.
This is still not efficient as it should be, because on every
HW change we drop all data structures and rebuild them from scratch
(which is not expensive because there aren't many of them, but
at least in the XRandR path it involves a few sync X calls)

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:22:54 +02:00
Giovanni Campagna
214f31257b Rework and consolidate monitor handling in MetaScreen
Consolidate all places that deal with output configuration in
MetaScreen, which gets it either from XRandR or from a dummy static configuration.
We still need to read the Xinerama config, even when running xwayland,
because we need the indices for _NET_WM_FULLSCREEN_MONITORS, but
now we do it only when needed.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
2013-08-18 00:22:54 +02:00
Giovanni Campagna
bfc87d13cb MetaWindowActor: fix reference counting issue
We need to use g_signal_connect_object(), rather than g_signal_connect(),
because the window actor can be destroyed before the window emits
the final notify::appears-focused inside unmanage, if the plugin
decides that it doesn't want to animate the destruction (which
happens with dialogs and the default plugin)

https://bugzilla.gnome.org/show_bug.cgi?id=706207
2013-08-18 00:22:07 +02:00
Giovanni Campagna
506ddc3d6c MetaWindowActor: fix reference counting issue
We need to use g_signal_connect_object(), rather than g_signal_connect(),
because the window actor can be destroyed before the window emits
the final notify::appears-focused inside unmanage, if the plugin
decides that it doesn't want to animate the destruction (which
happens with dialogs and the default plugin)

https://bugzilla.gnome.org/show_bug.cgi?id=706207
2013-08-18 00:16:59 +02:00
Colin Walters
24564c77d6 build: Fix srcdir != builddir
Need to ensure the wayland/ directory exists in $(builddir), and find
the headers there too.
2013-08-17 18:03:10 -04:00
Giovanni Campagna
18a21b67c2 wayland: move XWayland support code to its own file
Given that xwayland code is already split in meta-xwayland, it
makes sense to have there the implementation of the private
xserver protocol too.

https://bugzilla.gnome.org/show_bug.cgi?id=705816
2013-08-15 17:42:19 +02:00
Giovanni Campagna
3803fd9511 wayland: don't use fork() and SIGCHLD to spawn processes
It is a very bad idea in a glib program (especially one heavily
using glib child watching facilities, like gnome-shell) to handle
SIGCHLD. While we're there, let's also use g_spawn_async, which
solves some malloc-after-fork problems and makes the code generally
cleaner.

https://bugzilla.gnome.org/show_bug.cgi?id=705816
2013-08-15 17:41:34 +02:00
Giovanni Campagna
152d896f75 MetaWindowActor/wayland: make sure the mapped bit is correctly set
Otherwise it stays FALSE for OR windows, causing the shape region
to be empty and the actor culled from drawing.

https://bugzilla.gnome.org/show_bug.cgi?id=706078
2013-08-15 17:41:34 +02:00
Giovanni Campagna
2f3a5f2001 MetaWaylandSeat: correct logic to set the current / focused surface
The current surface refers to the surface right below the pointer
(according to the pick performed by clutter), while the focus surface
is the one receiving events. They can be out of sync in case of
grabs, in which case we should keep trying to focus the current
surface.

https://bugzilla.gnome.org/show_bug.cgi?id=706077
2013-08-15 17:41:34 +02:00
Piotr Drąg
c3e8646af3 Updated POTFILES.in 2013-08-13 21:10:02 +02:00
Alban Crequy
8c17b670fb keybindings: always acknowledge events to the X server
https://bugzilla.gnome.org/show_bug.cgi?id=666101
2013-08-13 11:18:48 -04:00
61 changed files with 2352 additions and 2873 deletions

10
.gitignore vendored
View File

@@ -23,7 +23,7 @@ src/50-mutter-navigation.xml
src/50-mutter-system.xml
src/50-mutter-windows.xml
src/mutter-wm.desktop
src/mutter.desktop
src/mutter-wayland.desktop
*.o
*.a
*.lo
@@ -46,10 +46,10 @@ POTFILES
po/*.pot
50-metacity-desktop-key.xml
50-metacity-key.xml
libmutter.pc
mutter
libmutter-wayland.pc
mutter-wayland
mutter-theme-viewer
mutter.desktop
mutter-wayland.desktop
org.gnome.mutter.gschema.valid
org.gnome.mutter.gschema.xml
testasyncgetprop
@@ -74,6 +74,8 @@ src/mutter-enum-types.[ch]
src/stamp-mutter-enum-types.h
src/mutter-marshal.[ch]
src/stamp-mutter-marshal.h
src/meta-dbus-xrandr.[ch]
src/meta-dbus-idle-monitor.[ch]
src/mutter-plugins.pc
doc/reference/*.args
doc/reference/*.bak

26
NEWS
View File

@@ -1,3 +1,29 @@
3.9.90
======
* First release from the wayland branch, includes basic support for running
as a wayland compositor [Robert, Neil, Giovanni]
* Add support for _GTK_FRAME_EXTENTS [Jasper; #705766]
* Fix quick consecutive <super> presses breaking keyboard input [Alban; #666101]
* Work towards running as wayland compositor [Giovanni]
- Add DBus API for display configuration
[#705670, #706231, #706233, #706322, #706382]
- Add abstraction layer for cursor tracking [#705911]
- Add support for plugin modality under wayland [#705917]
* Disable GTK+ scaling [Alexander; #706388]
* Disable blending while updating tower [Robert]
* Misc bug fixes and cleanups [Adel, Jasper, Giovanni, Colin, Rico, Florian;
#703332, #704437, #706207]
Contributors:
Robert Bragg, Giovanni Campagna, Alban Crequy, Adel Gadllah,
Alexander Larsson, Florian Müllner, Jasper St. Pierre, Neil Roberts,
Rico Tzschichholz, Colin Walters
Translations:
Jiro Matsuzawa [ja], Kjartan Maraas [nb], Matej Urbančič [sl],
Marek Černocký [cs], Daniel Mustieles [es], Rafael Ferreira [pt_BR],
Yaron Shahrabani [he], Ján Kyselica [sk]
3.9.5
=====
* Don't select for touch events on the stage [Jasper; #697192]

View File

@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [9])
m4_define([mutter_micro_version], [5])
m4_define([mutter_micro_version], [90])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -19,6 +19,10 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz tar-ustar])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AM_MAINTAINER_MODE([enable])
# Change pkglibdir and pkgdatadir to mutter-wayland instead of mutter
PACKAGE="mutter-wayland"
AC_SUBST([PACKAGE], [$PACKAGE])
MUTTER_MAJOR_VERSION=mutter_major_version
MUTTER_MINOR_VERSION=mutter_minor_version
MUTTER_MICRO_VERSION=mutter_micro_version
@@ -34,7 +38,7 @@ AC_SUBST(MUTTER_PLUGIN_DIR)
# Honor aclocal flags
AC_SUBST(ACLOCAL_AMFLAGS, "\${ACLOCAL_FLAGS}")
GETTEXT_PACKAGE=mutter
GETTEXT_PACKAGE=mutter-wayland
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Name of default gettext domain])
@@ -76,6 +80,7 @@ MUTTER_PC_MODULES="
$CLUTTER_PACKAGE >= 1.14.3
cogl-1.0 >= 1.13.3
upower-glib > 0.9.11
gnome-desktop-3.0
"
GLIB_GSETTINGS
@@ -114,11 +119,6 @@ AC_ARG_ENABLE(shape,
[disable mutter's use of the shaped window extension]),,
enable_shape=auto)
AC_ARG_ENABLE(wayland,
AC_HELP_STRING([--enable-wayland],
[Enable support for running as a hybrid X and Wayland compositor]),,
enable_wayland=no)
## Wayland support requires the xserver.xml protocol extension found in the weston
## repository but since there aren't currently established conventions for
## installing and discovering these we simply require a location to be given
@@ -141,6 +141,11 @@ AM_GLIB_GNU_GETTEXT
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
saved_LIBS="$LIBS"
LIBS="$LIBS $MUTTER_LAUNCH"
AC_CHECK_FUNCS([sd_session_get_vt])
LIBS="$saved_LIBS"
# Unconditionally use this dir to avoid a circular dep with gnomecc
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
AC_SUBST(GNOME_KEYBINDINGS_KEYSDIR)
@@ -218,29 +223,16 @@ if test x$have_xcursor = xyes; then
AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support])
fi
have_wayland=no
if test x$enable_wayland = "xyes"; then
WAYLAND_VERSION=0.1
AC_MSG_CHECKING([Wayland >= $WAYLAND_VERSION])
if ! $PKG_CONFIG --atleast-version $WAYLAND_VERSION wayland-server; then
AC_MSG_ERROR([wayland support enabled but no suitable wayland-server package found])
fi
AC_MSG_RESULT(yes)
# We always build with wayland enabled
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
AC_SUBST([WAYLAND_SCANNER])
AC_SUBST(XWAYLAND_PATH)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server libdrm"
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
have_wayland=yes
fi
AM_CONDITIONAL(HAVE_WAYLAND, test x$have_wayland = "xyes")
AC_PATH_PROG([WAYLAND_SCANNER],[wayland-scanner],[no])
AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_MSG_ERROR([Could not find wayland-scanner in your PATH, required for parsing wayland extension protocols]))
AC_SUBST([WAYLAND_SCANNER])
AC_SUBST(XWAYLAND_PATH)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server libdrm"
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
@@ -478,8 +470,7 @@ doc/man/Makefile
doc/reference/Makefile
doc/reference/meta-docs.sgml
src/Makefile
src/libmutter.pc
src/mutter-plugins.pc
src/libmutter-wayland.pc
src/compositor/plugins/Makefile
protocol/Makefile
data/Makefile
@@ -498,14 +489,12 @@ fi
dnl ==========================================================================
echo "
mutter-$VERSION
mutter-wayland-$VERSION
prefix: ${prefix}
source code location: ${srcdir}
compiler: ${CC}
Wayland: ${have_wayland}
Startup notification: ${have_startup_notification}
libcanberra: ${have_libcanberra}
Introspection: ${found_introspection}

View File

@@ -1,7 +1,3 @@
defaultcursordir = $(datadir)/mutter/cursors
defaultcursordir = $(pkgdatadir)/cursors
dist_defaultcursor_DATA =
if HAVE_WAYLAND
dist_defaultcursor_DATA += left_ptr.png
endif
dist_defaultcursor_DATA = left_ptr.png

View File

@@ -140,7 +140,7 @@ expand_content_files= \
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(MUTTER_CFLAGS)
GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter.la
GTKDOC_LIBS=$(MUTTER_LIBS) $(top_builddir)/src/libmutter-wayland.la
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make

View File

@@ -12,6 +12,7 @@ src/core/display.c
src/core/errors.c
src/core/keybindings.c
src/core/main.c
src/core/monitor.c
src/core/mutter.c
src/core/prefs.c
src/core/screen.c
@@ -23,12 +24,9 @@ src/core/xprops.c
src/mutter.desktop.in
src/mutter-wm.desktop.in
src/org.gnome.mutter.gschema.xml.in
src/tools/mutter-message.c
src/ui/frames.c
src/ui/menu.c
src/ui/metaaccellabel.c
src/ui/resizepopup.c
src/ui/theme.c
src/ui/theme-parser.c
src/ui/theme-viewer.c

View File

@@ -1,7 +1,7 @@
# Flag build for parallelism; see https://savannah.gnu.org/patch/?6905
.AUTOPARALLEL:
lib_LTLIBRARIES = libmutter.la
lib_LTLIBRARIES = libmutter-wayland.la
SUBDIRS=compositor/plugins
@@ -10,6 +10,7 @@ INCLUDES= \
-DCOGL_ENABLE_EXPERIMENTAL_API \
-DCOGL_ENABLE_EXPERIMENTAL_2_0_API \
$(MUTTER_CFLAGS) \
-I$(top_builddir) \
-I$(srcdir) \
-I$(srcdir)/core \
-I$(srcdir)/ui \
@@ -29,26 +30,21 @@ INCLUDES= \
-DMUTTER_PLUGIN_DIR=\"@MUTTER_PLUGIN_DIR@\" \
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\"
if HAVE_WAYLAND
INCLUDES += \
-I$(srcdir)/wayland \
-I$(builddir)/wayland \
-DXWAYLAND_PATH='"@XWAYLAND_PATH@"'
endif
mutter_built_sources = \
$(dbus_xrandr_built_sources) \
$(dbus_idle_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c
if HAVE_WAYLAND
mutter_built_sources += \
$(dbus_idle_built_sources) \
$(dbus_xrandr_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
wayland/xserver-protocol.c \
wayland/xserver-server-protocol.h \
wayland/xserver-client-protocol.h
endif
libmutter_la_SOURCES = \
libmutter_wayland_la_SOURCES = \
core/async-getprop.c \
core/async-getprop.h \
core/barrier.c \
@@ -77,6 +73,7 @@ libmutter_la_SOURCES = \
compositor/meta-shadow-factory.c \
compositor/meta-shadow-factory-private.h \
compositor/meta-shaped-texture.c \
compositor/meta-shaped-texture-private.h \
compositor/meta-texture-rectangle.c \
compositor/meta-texture-rectangle.h \
compositor/meta-texture-tower.c \
@@ -109,6 +106,8 @@ libmutter_la_SOURCES = \
ui/draw-workspace.h \
core/edge-resistance.c \
core/edge-resistance.h \
core/edid-parse.c \
core/edid.h \
core/errors.c \
meta/errors.h \
core/frame.c \
@@ -132,7 +131,6 @@ libmutter_la_SOURCES = \
core/meta-xrandr-shared.h \
core/monitor.c \
core/monitor-config.c \
core/monitor-kms.c \
core/monitor-private.h \
core/monitor-xrandr.c \
core/mutter-Xatomtype.h \
@@ -183,10 +181,7 @@ libmutter_la_SOURCES = \
ui/ui.c \
$(mutter_built_sources)
if HAVE_WAYLAND
libmutter_la_SOURCES += \
wayland/meta-tty.c \
wayland/meta-tty.h \
libmutter_wayland_la_SOURCES += \
wayland/meta-wayland.c \
wayland/meta-wayland-private.h \
wayland/meta-xwayland-private.h \
@@ -203,10 +198,9 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-stage.c \
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h
endif
libmutter_la_LDFLAGS = -no-undefined
libmutter_la_LIBADD = $(MUTTER_LIBS)
libmutter_wayland_la_LDFLAGS = -no-undefined
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
# Headers installed for plugins; introspected information will
# be extracted into Mutter-<version>.gir
@@ -244,29 +238,27 @@ libmutterinclude_base_headers = \
libmutterinclude_extra_headers = \
meta/atomnames.h
libmutterincludedir = $(includedir)/mutter/meta
libmutterincludedir = $(includedir)/mutter-wayland/meta
libmutterinclude_HEADERS = \
$(libmutterinclude_base_headers) \
$(libmutterinclude_extra_headers)
bin_PROGRAMS=mutter
bin_PROGRAMS=mutter-wayland
mutter_SOURCES = core/mutter.c
mutter_LDADD = $(MUTTER_LIBS) libmutter.la
mutter_wayland_SOURCES = core/mutter.c
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
if HAVE_WAYLAND
bin_PROGRAMS+=mutter-launch
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS)
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
endif
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)
@@ -288,15 +280,15 @@ typelib_DATA = Meta-$(api_version).typelib
INTROSPECTION_GIRS = Meta-$(api_version).gir
Meta-$(api_version).gir: libmutter.la
Meta-$(api_version).gir: libmutter-wayland.la
@META_GIR@_INCLUDES = GObject-2.0 GDesktopEnums-3.0 Gdk-3.0 Gtk-3.0 Clutter-1.0 xlib-2.0 xfixes-4.0 Cogl-1.0
@META_GIR@_EXPORT_PACKAGES = libmutter
@META_GIR@_EXPORT_PACKAGES = libmutter-wayland
@META_GIR@_CFLAGS = $(INCLUDES)
@META_GIR@_LIBS = libmutter.la
@META_GIR@_LIBS = libmutter-wayland.la
@META_GIR@_FILES = \
mutter-enum-types.h \
$(libmutterinclude_base_headers) \
$(filter %.c,$(libmutter_la_SOURCES))
$(filter %.c,$(libmutter_wayland_la_SOURCES))
@META_GIR@_SCANNERFLAGS = --warn-all --warn-error
endif
@@ -307,22 +299,17 @@ testasyncgetprop_SOURCES = core/testasyncgetprop.c
noinst_PROGRAMS=testboxes testgradient testasyncgetprop
testboxes_LDADD = $(MUTTER_LIBS) libmutter.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la
testboxes_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
testgradient_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
@INTLTOOL_DESKTOP_RULE@
desktopfilesdir=$(datadir)/applications
desktopfiles_in_files=mutter.desktop.in
desktopfiles_in_files=mutter-wayland.desktop.in
desktopfiles_files=$(desktopfiles_in_files:.desktop.in=.desktop)
desktopfiles_DATA = $(desktopfiles_files)
wmpropertiesdir=$(datadir)/gnome/wm-properties
wmproperties_in_files=mutter-wm.desktop.in
wmproperties_files=$(wmproperties_in_files:.desktop.in=.desktop)
wmproperties_DATA = $(wmproperties_files)
xmldir = @GNOME_KEYBINDINGS_KEYSDIR@
xml_in_files = \
50-mutter-navigation.xml.in \
@@ -330,7 +317,9 @@ xml_in_files = \
50-mutter-windows.xml.in
xml_DATA = $(xml_in_files:.xml.in=.xml)
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@
@GSETTINGS_RULES@
@@ -338,7 +327,7 @@ convertdir = $(datadir)/GConf/gsettings
convert_DATA = mutter-schemas.convert
CLEANFILES = \
mutter.desktop \
mutter-wayland.desktop \
mutter-wm.desktop \
org.gnome.mutter.gschema.xml \
$(xml_DATA) \
@@ -348,7 +337,7 @@ CLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libmutter.pc mutter-plugins.pc
pkgconfig_DATA = libmutter-wayland.pc
EXTRA_DIST=$(desktopfiles_files) \
$(wmproperties_files) \
@@ -358,8 +347,7 @@ EXTRA_DIST=$(desktopfiles_files) \
$(xml_in_files) \
org.gnome.mutter.gschema.xml.in \
mutter-schemas.convert \
libmutter.pc.in \
mutter-plugins.pc.in \
libmutter-wayland.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in
@@ -393,7 +381,7 @@ $(dbus_xrandr_built_sources) : Makefile.am xrandr.xml
--interface-prefix org.gnome.Mutter \
--c-namespace MetaDBus \
--generate-c-code meta-dbus-xrandr \
xrandr.xml
$(srcdir)/xrandr.xml
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
@@ -403,13 +391,14 @@ $(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
--c-namespace MetaDBus \
--generate-c-code meta-dbus-idle-monitor \
--c-generate-object-manager \
idle-monitor.xml
$(srcdir)/idle-monitor.xml
if HAVE_WAYLAND
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
wayland/%-server-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
wayland/%-client-protocol.h : $(top_builddir)/protocol/%.xml
mkdir -p wayland
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
endif

View File

@@ -84,11 +84,7 @@
#include "meta-window-group.h"
#include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-keyboard.h"
#endif
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
@@ -428,20 +424,34 @@ meta_stage_is_focused (MetaScreen *screen)
return (screen->display->focus_type == META_FOCUS_STAGE);
}
static gboolean
begin_modal_x11 (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaDisplay *display = meta_screen_get_display (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;
/* To some extent this duplicates code in meta_display_begin_grab_op(), but there
* are significant differences in how we handle grabs that make it difficult to
* merge the two.
*/
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdpy = meta_display_get_xdisplay (display);
MetaCompositor *compositor = display->compositor;
ClutterStage *stage;
Window grab_window;
Cursor cursor = None;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
int result;
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
if (!stage)
return FALSE;
grab_window = clutter_x11_get_stage_window (stage);
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
return FALSE;
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
@@ -491,79 +501,6 @@ begin_modal_x11 (MetaScreen *screen,
keyboard_grabbed = TRUE;
}
return TRUE;
fail:
if (pointer_grabbed)
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
if (keyboard_grabbed)
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
return FALSE;
}
static gboolean
begin_modal_wayland (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaWaylandCompositor *compositor;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
compositor = meta_wayland_compositor_get_default ();
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
goto fail;
pointer_grabbed = TRUE;
}
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard))
goto fail;
keyboard_grabbed = TRUE;
}
return TRUE;
fail:
if (pointer_grabbed)
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
if (keyboard_grabbed)
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard);
return FALSE;
}
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
/* To some extent this duplicates code in meta_display_begin_grab_op(), but there
* 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;
gboolean ok;
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
return FALSE;
if (meta_is_wayland_compositor ())
ok = begin_modal_wayland (screen, plugin, options, timestamp);
else
ok = begin_modal_x11 (screen, plugin, options, timestamp);
if (!ok)
return FALSE;
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->grab_window = NULL;
display->grab_screen = screen;
@@ -573,6 +510,14 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
compositor->modal_plugin = plugin;
return TRUE;
fail:
if (pointer_grabbed)
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
if (keyboard_grabbed)
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
return FALSE;
}
void
@@ -586,18 +531,8 @@ meta_end_modal_for_plugin (MetaScreen *screen,
g_return_if_fail (compositor->modal_plugin == plugin);
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard);
}
else
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
}
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL;
@@ -694,11 +629,9 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
MetaCompScreen *info;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
Window xwin = None;
Window xwin;
gint width, height;
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *wayland_compositor;
#endif
/* Check if the screen is already managed */
if (meta_screen_get_compositor_data (screen))
@@ -731,7 +664,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
/* We will have already created a stage if running as a wayland
* compositor... */
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
wayland_compositor = meta_wayland_compositor_get_default ();
@@ -741,7 +673,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
clutter_actor_set_size (info->stage, width, height);
}
else
#endif /* HAVE_WAYLAND */
{
info->stage = clutter_stage_new ();
@@ -840,8 +771,6 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
redirect_windows (compositor, screen);
}
clutter_actor_show (info->stage);
}
void
@@ -1490,6 +1419,7 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
guint width,
guint height)
{
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (meta_is_wayland_compositor ())
@@ -1508,7 +1438,6 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
}
else
{
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay;
Window xwin;

View File

@@ -1031,7 +1031,6 @@ meta_background_load_file_finish (MetaBackground *self,
GAsyncResult *result,
GError **error)
{
static CoglUserDataKey key;
GTask *task;
LoadFileTaskData *task_data;
CoglTexture *texture;
@@ -1077,12 +1076,6 @@ meta_background_load_file_finish (MetaBackground *self,
goto out;
}
cogl_object_set_user_data (COGL_OBJECT (texture),
&key,
g_object_ref (pixbuf),
(CoglUserDataDestroyCallback)
g_object_unref);
ensure_pipeline (self);
unset_texture (self);
set_style (self, task_data->style);

View File

@@ -0,0 +1,44 @@
/*
* shaped texture
*
* An actor to draw a texture clipped to a list of rectangles
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2008 Intel Corporation
* 2013 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_SHAPED_TEXTURE_PRIVATE_H__
#define __META_SHAPED_TEXTURE_PRIVATE_H__
#include <meta/meta-shaped-texture.h>
#include "meta-wayland-private.h"
ClutterActor *meta_shaped_texture_new_with_xwindow (Window xwindow);
ClutterActor *meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface);
void meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
MetaWaylandSurface *surface);
MetaWaylandSurface *meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex);
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
Pixmap pixmap);
void meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
MetaWaylandBuffer *buffer);
#endif

View File

@@ -33,10 +33,9 @@
#include <meta/util.h>
#include "meta-texture-tower.h"
#ifdef HAVE_WAYLAND
#include "meta-shaped-texture-private.h"
#include "meta-wayland-private.h"
#include <cogl/cogl-wayland-server.h>
#endif
#include <clutter/clutter.h>
#include <cogl/cogl.h>
@@ -64,9 +63,7 @@ static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, Clutte
typedef enum _MetaShapedTextureType
{
META_SHAPED_TEXTURE_TYPE_X11_PIXMAP,
#ifdef HAVE_WAYLAND
META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE,
#endif
} MetaShapedTextureType;
@@ -86,11 +83,9 @@ struct _MetaShapedTexturePrivate
struct {
Pixmap pixmap;
} x11;
#ifdef HAVE_WAYLAND
struct {
MetaWaylandSurface *surface;
} wayland;
#endif
};
CoglTexture *texture;
@@ -462,7 +457,6 @@ meta_shaped_texture_get_paint_volume (ClutterActor *self,
return clutter_paint_volume_set_from_allocation (volume, self);
}
#ifdef HAVE_WAYLAND
ClutterActor *
meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface)
{
@@ -498,7 +492,6 @@ meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex)
MetaShapedTexturePrivate *priv = stex->priv;
return priv->wayland.surface;
}
#endif /* HAVE_WAYLAND */
ClutterActor *
meta_shaped_texture_new_with_xwindow (Window xwindow)
@@ -548,7 +541,6 @@ meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
}
#ifdef HAVE_WAYLAND
static void
wayland_surface_update_area (MetaShapedTexture *stex,
int x,
@@ -608,7 +600,6 @@ wayland_surface_update_area (MetaShapedTexture *stex,
}
}
}
#endif /* HAVE_WAYLAND */
static void
queue_damage_redraw_with_clip (MetaShapedTexture *stex,
@@ -678,11 +669,9 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
cogl_texture_pixmap_x11_update_area (COGL_TEXTURE_PIXMAP_X11 (priv->texture),
x, y, width, height);
break;
#ifdef HAVE_WAYLAND
case META_SHAPED_TEXTURE_TYPE_WAYLAND_SURFACE:
wayland_surface_update_area (stex, x, y, width, height);
break;
#endif
}
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
@@ -726,7 +715,6 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
COGL_TEXTURE (priv->texture));
}
#ifdef HAVE_WAYLAND
void
meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
MetaWaylandBuffer *buffer)
@@ -772,7 +760,6 @@ meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
meta_texture_tower_set_base_texture (priv->paint_tower,
COGL_TEXTURE (priv->texture));
}
#endif /* HAVE_WAYLAND */
/**
* meta_shaped_texture_get_texture:

View File

@@ -5,10 +5,8 @@
#include <config.h>
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
#include <meta-wayland-private.h>
#endif
#include <X11/extensions/Xdamage.h>
#include <meta/compositor-mutter.h>
@@ -32,7 +30,6 @@ void meta_window_actor_unmaximize (MetaWindowActor *self,
void meta_window_actor_process_x11_damage (MetaWindowActor *self,
XDamageNotifyEvent *event);
#ifdef HAVE_WAYLAND
void meta_window_actor_process_wayland_damage (MetaWindowActor *self,
int x,
int y,
@@ -42,7 +39,6 @@ void meta_window_actor_set_wayland_surface (MetaWindowActor *self,
MetaWaylandSurface *surface);
void meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
MetaWaylandBuffer *buffer);
#endif
void meta_window_actor_pre_paint (MetaWindowActor *self);
void meta_window_actor_post_paint (MetaWindowActor *self);

View File

@@ -28,13 +28,12 @@
#include "xprops.h"
#include "compositor-private.h"
#include "meta-shaped-texture-private.h"
#include "meta-shadow-factory-private.h"
#include "meta-window-actor-private.h"
#include "meta-texture-rectangle.h"
#include "region-utils.h"
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
enum {
POSITION_CHANGED,
@@ -371,11 +370,9 @@ meta_window_actor_constructed (GObject *object)
if (!priv->actor)
{
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
priv->actor = meta_shaped_texture_new_with_wayland_surface (window->surface);
else
#endif
priv->actor = meta_shaped_texture_new_with_xwindow (xwindow);
clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor);
@@ -392,10 +389,10 @@ meta_window_actor_constructed (GObject *object)
*/
g_object_ref (priv->actor);
g_signal_connect (window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self);
g_signal_connect (window, "notify::appears-focused",
G_CALLBACK (window_appears_focused_notify), self);
g_signal_connect_object (window, "notify::decorated",
G_CALLBACK (window_decorated_notify), self, 0);
g_signal_connect_object (window, "notify::appears-focused",
G_CALLBACK (window_appears_focused_notify), self, 0);
}
else
{
@@ -1320,10 +1317,8 @@ meta_window_actor_destroy (MetaWindowActor *self)
priv = self->priv;
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
meta_shaped_texture_set_wayland_surface (META_SHAPED_TEXTURE (priv->actor), NULL);
#endif
window = priv->window;
window_type = meta_window_get_window_type (window);
@@ -1567,14 +1562,12 @@ meta_window_actor_new (MetaWindow *window)
meta_verbose ("add window: Meta %p, xwin 0x%x\n", window, (guint)top_window);
}
#ifdef HAVE_WAYLAND
else
{
meta_verbose ("add window: Meta %p, wayland surface %p\n",
window, window->surface);
top_window = None;
}
#endif
self = g_object_new (META_TYPE_WINDOW_ACTOR,
"meta-window", window,
@@ -1583,13 +1576,13 @@ meta_window_actor_new (MetaWindow *window)
NULL);
priv = self->priv;
priv->mapped = meta_window_toplevel_is_mapped (priv->window);
if (!meta_is_wayland_compositor ())
{
priv->last_width = -1;
priv->last_height = -1;
priv->mapped = meta_window_toplevel_is_mapped (priv->window);
if (priv->mapped)
meta_window_actor_queue_create_x11_pixmap (self);
@@ -2022,7 +2015,6 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
priv->repaint_scheduled = TRUE;
}
#ifdef HAVE_WAYLAND
void
meta_window_actor_process_wayland_damage (MetaWindowActor *self,
int x,
@@ -2039,7 +2031,6 @@ meta_window_actor_process_wayland_damage (MetaWindowActor *self,
x, y, width, height);
priv->repaint_scheduled = TRUE;
}
#endif
void
meta_window_actor_sync_visibility (MetaWindowActor *self)
@@ -2429,7 +2420,6 @@ meta_window_actor_update_shape (MetaWindowActor *self)
clutter_actor_queue_redraw (priv->actor);
}
#ifdef HAVE_WAYLAND
static void
maybe_emit_size_changed (MetaWindowActor *self,
MetaWaylandBuffer *new_buffer)
@@ -2490,7 +2480,6 @@ meta_window_actor_attach_wayland_buffer (MetaWindowActor *self,
maybe_emit_size_changed (self, buffer);
}
#endif /* HAVE_WAYLAND */
static void
meta_window_actor_handle_updates (MetaWindowActor *self)

View File

@@ -187,7 +187,7 @@ meta_window_group_paint (ClutterActor *actor)
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindow *meta_window;
MetaWindowActor *window_actor = child;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
int x, y;
if (!meta_actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))

View File

@@ -27,7 +27,6 @@
#include <meta/meta-background-group.h>
#include <meta/meta-background-actor.h>
#include <stdlib.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x

View File

@@ -518,7 +518,7 @@ meta_display_open (void)
if (meta_is_syncing ())
XSynchronize (xdisplay, True);
g_assert (the_display == NULL);
the_display = g_object_new (META_TYPE_DISPLAY, NULL);
@@ -991,8 +991,10 @@ meta_display_open (void)
meta_error_trap_pop (the_display);
}
meta_display_ungrab (the_display);
meta_idle_monitor_init_dbus ();
meta_display_ungrab (the_display);
/* Done opening new display */
the_display->display_opening = FALSE;
@@ -1904,9 +1906,7 @@ update_focus_window (MetaDisplay *display,
Window xwindow,
gulong serial)
{
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *compositor;
#endif
display->focus_serial = serial;
@@ -1947,7 +1947,6 @@ update_focus_window (MetaDisplay *display,
else
meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial);
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
compositor = meta_wayland_compositor_get_default ();
@@ -1960,7 +1959,6 @@ update_focus_window (MetaDisplay *display,
else
meta_topic (META_DEBUG_FOCUS, "Focus change has no effect, because there is no matching wayland surface");
}
#endif
g_object_notify (G_OBJECT (display), "focus-window");
meta_display_update_active_window_hint (display);
@@ -2317,8 +2315,8 @@ meta_display_handle_event (MetaDisplay *display,
meta_window_update_sync_request_counter (alarm_window, new_counter_value);
filter_out_event = TRUE; /* GTK doesn't want to see this really */
}
meta_idle_monitor_handle_xevent_all (event);
else
meta_idle_monitor_handle_xevent_all (event);
}
#endif /* HAVE_XSYNC */
@@ -3231,12 +3229,10 @@ event_callback (XEvent *event,
erratically because of the lag between updating the window
position from the surface position. Instead we bypass the
translation altogether by directly using the Clutter events */
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () &&
event->type == GenericEvent &&
event->xcookie.evtype == XI_Motion)
return FALSE;
#endif
return meta_display_handle_event (display, event);
}

539
src/core/edid-parse.c Normal file
View File

@@ -0,0 +1,539 @@
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
#include "edid.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <glib.h>
static int
get_bit (int in, int bit)
{
return (in & (1 << bit)) >> bit;
}
static int
get_bits (int in, int begin, int end)
{
int mask = (1 << (end - begin + 1)) - 1;
return (in >> begin) & mask;
}
static int
decode_header (const uchar *edid)
{
if (memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
return TRUE;
return FALSE;
}
static int
decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
{
int is_model_year;
/* Manufacturer Code */
info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
info->manufacturer_code[3] = '\0';
info->manufacturer_code[0] += 'A' - 1;
info->manufacturer_code[1] += 'A' - 1;
info->manufacturer_code[2] += 'A' - 1;
/* Product Code */
info->product_code = edid[0x0b] << 8 | edid[0x0a];
/* Serial Number */
info->serial_number =
edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | edid[0x0f] << 24;
/* Week and Year */
is_model_year = FALSE;
switch (edid[0x10])
{
case 0x00:
info->production_week = -1;
break;
case 0xff:
info->production_week = -1;
is_model_year = TRUE;
break;
default:
info->production_week = edid[0x10];
break;
}
if (is_model_year)
{
info->production_year = -1;
info->model_year = 1990 + edid[0x11];
}
else
{
info->production_year = 1990 + edid[0x11];
info->model_year = -1;
}
return TRUE;
}
static int
decode_edid_version (const uchar *edid, MonitorInfo *info)
{
info->major_version = edid[0x12];
info->minor_version = edid[0x13];
return TRUE;
}
static int
decode_display_parameters (const uchar *edid, MonitorInfo *info)
{
/* Digital vs Analog */
info->is_digital = get_bit (edid[0x14], 7);
if (info->is_digital)
{
int bits;
static const int bit_depth[8] =
{
-1, 6, 8, 10, 12, 14, 16, -1
};
static const Interface interfaces[6] =
{
UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
};
bits = get_bits (edid[0x14], 4, 6);
info->connector.digital.bits_per_primary = bit_depth[bits];
bits = get_bits (edid[0x14], 0, 3);
if (bits <= 5)
info->connector.digital.interface = interfaces[bits];
else
info->connector.digital.interface = UNDEFINED;
}
else
{
int bits = get_bits (edid[0x14], 5, 6);
static const double levels[][3] =
{
{ 0.7, 0.3, 1.0 },
{ 0.714, 0.286, 1.0 },
{ 1.0, 0.4, 1.4 },
{ 0.7, 0.0, 0.7 },
};
info->connector.analog.video_signal_level = levels[bits][0];
info->connector.analog.sync_signal_level = levels[bits][1];
info->connector.analog.total_signal_level = levels[bits][2];
info->connector.analog.blank_to_black = get_bit (edid[0x14], 4);
info->connector.analog.separate_hv_sync = get_bit (edid[0x14], 3);
info->connector.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
info->connector.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
info->connector.analog.serration_on_vsync = get_bit (edid[0x14], 0);
}
/* Screen Size / Aspect Ratio */
if (edid[0x15] == 0 && edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = -1.0;
}
else if (edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
}
else if (edid[0x15] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x16] + 99);
info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
}
else
{
info->width_mm = 10 * edid[0x15];
info->height_mm = 10 * edid[0x16];
}
/* Gamma */
if (edid[0x17] == 0xFF)
info->gamma = -1.0;
else
info->gamma = (edid[0x17] + 100.0) / 100.0;
/* Features */
info->standby = get_bit (edid[0x18], 7);
info->suspend = get_bit (edid[0x18], 6);
info->active_off = get_bit (edid[0x18], 5);
if (info->is_digital)
{
info->connector.digital.rgb444 = TRUE;
if (get_bit (edid[0x18], 3))
info->connector.digital.ycrcb444 = 1;
if (get_bit (edid[0x18], 4))
info->connector.digital.ycrcb422 = 1;
}
else
{
int bits = get_bits (edid[0x18], 3, 4);
ColorType color_type[4] =
{
MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
};
info->connector.analog.color_type = color_type[bits];
}
info->srgb_is_standard = get_bit (edid[0x18], 2);
/* In 1.3 this is called "has preferred timing" */
info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
/* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
info->continuous_frequency = get_bit (edid[0x18], 0);
return TRUE;
}
static double
decode_fraction (int high, int low)
{
double result = 0.0;
int i;
high = (high << 2) | low;
for (i = 0; i < 10; ++i)
result += get_bit (high, i) * pow (2, i - 10);
return result;
}
static int
decode_color_characteristics (const uchar *edid, MonitorInfo *info)
{
info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
return TRUE;
}
static int
decode_established_timings (const uchar *edid, MonitorInfo *info)
{
static const Timing established[][8] =
{
{
{ 800, 600, 60 },
{ 800, 600, 56 },
{ 640, 480, 75 },
{ 640, 480, 72 },
{ 640, 480, 67 },
{ 640, 480, 60 },
{ 720, 400, 88 },
{ 720, 400, 70 }
},
{
{ 1280, 1024, 75 },
{ 1024, 768, 75 },
{ 1024, 768, 70 },
{ 1024, 768, 60 },
{ 1024, 768, 87 },
{ 832, 624, 75 },
{ 800, 600, 75 },
{ 800, 600, 72 }
},
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1152, 870, 75 }
},
};
int i, j, idx;
idx = 0;
for (i = 0; i < 3; ++i)
{
for (j = 0; j < 8; ++j)
{
int byte = edid[0x23 + i];
if (get_bit (byte, j) && established[i][j].frequency != 0)
info->established[idx++] = established[i][j];
}
}
return TRUE;
}
static int
decode_standard_timings (const uchar *edid, MonitorInfo *info)
{
int i;
for (i = 0; i < 8; i++)
{
int first = edid[0x26 + 2 * i];
int second = edid[0x27 + 2 * i];
if (first != 0x01 && second != 0x01)
{
int w = 8 * (first + 31);
int h = 0;
switch (get_bits (second, 6, 7))
{
case 0x00: h = (w / 16) * 10; break;
case 0x01: h = (w / 4) * 3; break;
case 0x02: h = (w / 5) * 4; break;
case 0x03: h = (w / 16) * 9; break;
}
info->standard[i].width = w;
info->standard[i].height = h;
info->standard[i].frequency = get_bits (second, 0, 5) + 60;
}
}
return TRUE;
}
static void
decode_lf_string (const uchar *s, int n_chars, char *result)
{
int i;
for (i = 0; i < n_chars; ++i)
{
if (s[i] == 0x0a)
{
*result++ = '\0';
break;
}
else if (s[i] == 0x00)
{
/* Convert embedded 0's to spaces */
*result++ = ' ';
}
else
{
*result++ = s[i];
}
}
}
static void
decode_display_descriptor (const uchar *desc,
MonitorInfo *info)
{
switch (desc[0x03])
{
case 0xFC:
decode_lf_string (desc + 5, 13, info->dsc_product_name);
break;
case 0xFF:
decode_lf_string (desc + 5, 13, info->dsc_serial_number);
break;
case 0xFE:
decode_lf_string (desc + 5, 13, info->dsc_string);
break;
case 0xFD:
/* Range Limits */
break;
case 0xFB:
/* Color Point */
break;
case 0xFA:
/* Timing Identifications */
break;
case 0xF9:
/* Color Management */
break;
case 0xF8:
/* Timing Codes */
break;
case 0xF7:
/* Established Timings */
break;
case 0x10:
break;
}
}
static void
decode_detailed_timing (const uchar *timing,
DetailedTiming *detailed)
{
int bits;
StereoType stereo[] =
{
NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
};
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
detailed->v_front_porch =
get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
detailed->v_sync =
get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
detailed->right_border = timing[0x0f];
detailed->top_border = timing[0x10];
detailed->interlaced = get_bit (timing[0x11], 7);
/* Stereo */
bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
detailed->stereo = stereo[bits];
/* Sync */
bits = timing[0x11];
detailed->digital_sync = get_bit (bits, 4);
if (detailed->digital_sync)
{
detailed->connector.digital.composite = !get_bit (bits, 3);
if (detailed->connector.digital.composite)
{
detailed->connector.digital.serrations = get_bit (bits, 2);
detailed->connector.digital.negative_vsync = FALSE;
}
else
{
detailed->connector.digital.serrations = FALSE;
detailed->connector.digital.negative_vsync = !get_bit (bits, 2);
}
detailed->connector.digital.negative_hsync = !get_bit (bits, 0);
}
else
{
detailed->connector.analog.bipolar = get_bit (bits, 3);
detailed->connector.analog.serrations = get_bit (bits, 2);
detailed->connector.analog.sync_on_green = !get_bit (bits, 1);
}
}
static int
decode_descriptors (const uchar *edid, MonitorInfo *info)
{
int i;
int timing_idx;
timing_idx = 0;
for (i = 0; i < 4; ++i)
{
int index = 0x36 + i * 18;
if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
{
decode_display_descriptor (edid + index, info);
}
else
{
decode_detailed_timing (edid + index, &(info->detailed_timings[timing_idx++]));
}
}
info->n_detailed_timings = timing_idx;
return TRUE;
}
static void
decode_check_sum (const uchar *edid,
MonitorInfo *info)
{
int i;
uchar check = 0;
for (i = 0; i < 128; ++i)
check += edid[i];
info->checksum = check;
}
MonitorInfo *
decode_edid (const uchar *edid)
{
MonitorInfo *info = g_new0 (MonitorInfo, 1);
decode_check_sum (edid, info);
if (decode_header (edid)
&& decode_vendor_and_product_identification (edid, info)
&& decode_edid_version (edid, info)
&& decode_display_parameters (edid, info)
&& decode_color_characteristics (edid, info)
&& decode_established_timings (edid, info)
&& decode_standard_timings (edid, info)
&& decode_descriptors (edid, info))
{
return info;
}
else
{
g_free (info);
return NULL;
}
}

195
src/core/edid.h Normal file
View File

@@ -0,0 +1,195 @@
/* edid.h
*
* Copyright 2007, 2008, Red Hat, Inc.
*
* This file is part of the Gnome Library.
*
* The Gnome Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The Gnome 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Gnome Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#ifndef EDID_H
#define EDID_H
typedef unsigned char uchar;
typedef struct MonitorInfo MonitorInfo;
typedef struct Timing Timing;
typedef struct DetailedTiming DetailedTiming;
typedef enum
{
UNDEFINED,
DVI,
HDMI_A,
HDMI_B,
MDDI,
DISPLAY_PORT
} Interface;
typedef enum
{
UNDEFINED_COLOR,
MONOCHROME,
RGB,
OTHER_COLOR
} ColorType;
typedef enum
{
NO_STEREO,
FIELD_RIGHT,
FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN,
TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED,
SIDE_BY_SIDE
} StereoType;
struct Timing
{
int width;
int height;
int frequency;
};
struct DetailedTiming
{
int pixel_clock;
int h_addr;
int h_blank;
int h_sync;
int h_front_porch;
int v_addr;
int v_blank;
int v_sync;
int v_front_porch;
int width_mm;
int height_mm;
int right_border;
int top_border;
int interlaced;
StereoType stereo;
int digital_sync;
union
{
struct
{
int bipolar;
int serrations;
int sync_on_green;
} analog;
struct
{
int composite;
int serrations;
int negative_vsync;
int negative_hsync;
} digital;
} connector;
};
struct MonitorInfo
{
int checksum;
char manufacturer_code[4];
int product_code;
unsigned int serial_number;
int production_week; /* -1 if not specified */
int production_year; /* -1 if not specified */
int model_year; /* -1 if not specified */
int major_version;
int minor_version;
int is_digital;
union
{
struct
{
int bits_per_primary;
Interface interface;
int rgb444;
int ycrcb444;
int ycrcb422;
} digital;
struct
{
double video_signal_level;
double sync_signal_level;
double total_signal_level;
int blank_to_black;
int separate_hv_sync;
int composite_sync_on_h;
int composite_sync_on_green;
int serration_on_vsync;
ColorType color_type;
} analog;
} connector;
int width_mm; /* -1 if not specified */
int height_mm; /* -1 if not specified */
double aspect_ratio; /* -1.0 if not specififed */
double gamma; /* -1.0 if not specified */
int standby;
int suspend;
int active_off;
int srgb_is_standard;
int preferred_timing_includes_native;
int continuous_frequency;
double red_x;
double red_y;
double green_x;
double green_y;
double blue_x;
double blue_y;
double white_x;
double white_y;
Timing established[24]; /* Terminated by 0x0x0 */
Timing standard[8];
int n_detailed_timings;
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
* mode, it is the first one
* (whether it has, is
* determined by the
* preferred_timing_includes
* bit.
*/
/* Optional product description */
char dsc_serial_number[14];
char dsc_product_name[14];
char dsc_string[14]; /* Unspecified ASCII data */
};
MonitorInfo *decode_edid (const uchar *data);
char *make_display_name (const MonitorInfo *info);
char *make_display_size_string (int width_mm, int height_mm);
#endif

View File

@@ -59,6 +59,7 @@
#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"
static gboolean add_builtin_keybinding (MetaDisplay *display,
const char *name,
@@ -1969,6 +1970,23 @@ process_overlay_key (MetaDisplay *display,
return TRUE;
meta_display_overlay_key_activate (display);
}
else
{
/* In some rare race condition, mutter might not receive the Super_L
* KeyRelease event because:
* - the compositor might end the modal mode and call XIUngrabDevice
* while the key is still down
* - passive grabs are only activated on KeyPress and not KeyRelease.
*
* In this case, display->overlay_key_only_pressed might be wrong.
* Mutter still ought to acknowledge events, otherwise the X server
* will not send the next events.
*
* https://bugzilla.gnome.org/show_bug.cgi?id=666101
*/
XIAllowEvents (display->xdisplay, event->deviceid,
XIAsyncDevice, event->time);
}
return TRUE;
}
@@ -4096,17 +4114,17 @@ handle_switch_vt (MetaDisplay *display,
{
gint vt = binding->handler->data;
MetaWaylandCompositor *compositor;
MetaTTY *tty;
MetaLauncher *launcher;
compositor = meta_wayland_compositor_get_default ();
tty = meta_wayland_compositor_get_tty (compositor);
launcher = meta_wayland_compositor_get_launcher (compositor);
if (tty)
if (launcher)
{
GError *error;
error = NULL;
if (!meta_tty_activate_vt (tty, vt, &error))
if (!meta_launcher_activate_vt (launcher, vt, &error))
{
g_warning ("Failed to switch VT: %s", error->message);
g_error_free (error);
@@ -4182,6 +4200,7 @@ init_builtin_key_bindings (MetaDisplay *display)
META_KEY_BINDING_IS_REVERSED)
GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS);
GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS);
GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS);
add_builtin_keybinding (display,
"switch-to-workspace-1",
@@ -4448,49 +4467,49 @@ init_builtin_key_bindings (MetaDisplay *display)
{
add_builtin_keybinding (display,
"switch-to-session-1",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 1);
add_builtin_keybinding (display,
"switch-to-session-2",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 2);
add_builtin_keybinding (display,
"switch-to-session-3",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 3);
add_builtin_keybinding (display,
"switch-to-session-4",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 4);
add_builtin_keybinding (display,
"switch-to-session-5",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 5);
add_builtin_keybinding (display,
"switch-to-session-6",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 6);
add_builtin_keybinding (display,
"switch-to-session-7",
mutter_keybindings,
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 7);

View File

@@ -55,9 +55,7 @@
#include "session.h"
#include <meta/prefs.h>
#include <meta/compositor.h>
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
#include <glib-object.h>
#include <glib-unix.h>
@@ -351,10 +349,8 @@ meta_finalize (void)
meta_display_close (display,
CurrentTime); /* I doubt correct timestamps matter here */
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
meta_wayland_finalize ();
#endif
}
static gboolean
@@ -365,28 +361,6 @@ on_sigterm (gpointer user_data)
return G_SOURCE_REMOVE;
}
static void
crash_handler (int signum)
{
char buffer[256];
MetaWaylandCompositor *compositor;
MetaTTY *tty;
snprintf (buffer, 256, "Fatal server error: %d\n", signum);
write (STDERR_FILENO, buffer, strlen (buffer));
compositor = meta_wayland_compositor_get_default ();
tty = meta_wayland_compositor_get_tty (compositor);
/* Passing FALSE ensures that we only do ioctls, which is
safe from a signal handler */
if (tty)
meta_tty_reset (tty, FALSE);
/* We can't continue with the default handling, so just exit here */
_exit(1);
}
/**
* meta_init: (skip)
*
@@ -412,19 +386,6 @@ meta_init (void)
g_strerror (errno));
#endif
if (meta_is_wayland_compositor ())
{
act.sa_handler = crash_handler;
/* Ignore if we can't register signal handlers, worse
that can happen one needs the sysrq to get out of the VT */
sigaction (SIGABRT, &act, NULL);
sigaction (SIGSEGV, &act, NULL);
sigaction (SIGBUS, &act, NULL);
sigaction (SIGFPE, &act, NULL);
sigaction (SIGTRAP, &act, NULL);
}
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
if (g_getenv ("MUTTER_VERBOSE"))
@@ -443,7 +404,6 @@ meta_init (void)
g_irepository_prepend_search_path (MUTTER_PKGLIBDIR);
#endif
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
/* NB: When running as a hybrid wayland compositor we run our own headless X
@@ -451,7 +411,6 @@ meta_init (void)
meta_wayland_init ();
}
else
#endif
meta_select_display (opt_display_name);
meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL));

View File

@@ -25,6 +25,7 @@
#define META_CURSOR_TRACKER_PRIVATE_H
#include <meta/meta-cursor-tracker.h>
#include <clutter/clutter.h>
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
XEvent *xevent);

View File

@@ -39,7 +39,10 @@
#include "meta-cursor-tracker-private.h"
#include "screen-private.h"
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
@@ -123,6 +126,7 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
G_TYPE_NONE, 0);
}
#ifdef HAVE_WAYLAND
static MetaCursorTracker *
make_wayland_cursor_tracker (MetaScreen *screen)
{
@@ -139,6 +143,7 @@ make_wayland_cursor_tracker (MetaScreen *screen)
return self;
}
#endif
static MetaCursorTracker *
make_x11_cursor_tracker (MetaScreen *screen)
@@ -169,9 +174,11 @@ meta_cursor_tracker_get_for_screen (MetaScreen *screen)
if (screen->cursor_tracker)
return screen->cursor_tracker;
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
self = make_wayland_cursor_tracker (screen);
else
#endif
self = make_x11_cursor_tracker (screen);
screen->cursor_tracker = self;
@@ -312,8 +319,8 @@ ensure_wayland_cursor (MetaCursorTracker *tracker)
if (tracker->default_cursor)
return;
filename = g_build_filename (MUTTER_DATADIR,
"mutter/cursors/left_ptr.png",
filename = g_build_filename (MUTTER_PKGDATADIR,
"cursors/left_ptr.png",
NULL);
bitmap = cogl_bitmap_new_from_file (filename, NULL);

View File

@@ -104,25 +104,26 @@ _xsyncvalue_to_int64 (XSyncValue value)
| (guint64) XSyncValueLow32 (value);
}
#define GINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, value, ((guint64)value) >> 32)
#define GUINT64_TO_XSYNCVALUE(value, ret) XSyncIntsToValue (ret, (value) & 0xFFFFFFFF, ((guint64)(value)) >> 32)
static void
fire_watch (MetaIdleMonitorWatch *watch)
{
MetaIdleMonitor *monitor;
guint id;
gboolean is_user_active_watch;
monitor = watch->monitor;
g_object_ref (monitor);
if (watch->callback)
{
watch->callback (watch->monitor,
watch->id,
watch->user_data);
}
id = watch->id;
is_user_active_watch = (watch->timeout_msec == 0);
if (watch->timeout_msec == 0)
meta_idle_monitor_remove_watch (watch->monitor, watch->id);
if (watch->callback)
watch->callback (monitor, id, watch->user_data);
if (is_user_active_watch)
meta_idle_monitor_remove_watch (monitor, id);
g_object_unref (monitor);
}
@@ -146,7 +147,7 @@ _xsync_alarm_set (MetaIdleMonitor *monitor,
attr.delta = delta;
attr.events = want_events;
GINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
GUINT64_TO_XSYNCVALUE (interval, &attr.trigger.wait_value);
attr.trigger.test_type = test_type;
return XSyncCreateAlarm (monitor->display, flags, &attr);
}
@@ -219,7 +220,7 @@ meta_idle_monitor_handle_xevent (MetaIdleMonitor *monitor,
{
watches = g_hash_table_get_values (monitor->watches);
g_list_foreach (watches, check_x11_watch, monitor);
g_list_foreach (watches, check_x11_watch, (gpointer) alarm);
g_list_free (watches);
}
}
@@ -308,7 +309,10 @@ init_xsync (MetaIdleMonitor *monitor)
monitor->counter = find_idletime_counter (monitor);
/* IDLETIME counter not found? */
if (monitor->counter == None)
return;
{
meta_warning ("IDLETIME counter not found\n");
return;
}
monitor->user_active_alarm = _xsync_alarm_set (monitor, XSyncNegativeTransition, 1, FALSE);
}
@@ -632,7 +636,7 @@ meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
*
* Returns: The current idle time, in milliseconds, or -1 for not supported
*/
guint64
gint64
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
{
XSyncValue value;
@@ -787,7 +791,7 @@ make_dbus_watch (MetaDBusIdleMonitor *skeleton,
static gboolean
handle_add_idle_watch (MetaDBusIdleMonitor *skeleton,
GDBusMethodInvocation *invocation,
guint64 interval,
guint64 interval,
MetaIdleMonitor *monitor)
{
DBusWatch *watch;
@@ -831,30 +835,12 @@ handle_remove_watch (MetaDBusIdleMonitor *skeleton,
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
GDBusObjectManagerServer *manager)
create_monitor_skeleton (GDBusObjectManagerServer *manager,
MetaIdleMonitor *monitor,
const char *path)
{
MetaDBusIdleMonitor *skeleton;
MetaIdleMonitor *monitor;
MetaDBusObjectSkeleton *object;
int device_id;
gboolean is_core;
char *path;
is_core = clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER;
if (is_core)
{
monitor = meta_idle_monitor_get_core ();
path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
}
else
{
device_id = clutter_input_device_get_device_id (device);
monitor = meta_idle_monitor_get_for_device (device_id);
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
}
skeleton = meta_dbus_idle_monitor_skeleton_new ();
g_signal_connect_object (skeleton, "handle-add-idle-watch",
@@ -872,6 +858,42 @@ on_device_added (ClutterDeviceManager *device_manager,
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
GDBusObjectManagerServer *manager)
{
MetaIdleMonitor *monitor;
int device_id;
char *path;
device_id = clutter_input_device_get_device_id (device);
monitor = meta_idle_monitor_get_for_device (device_id);
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
create_monitor_skeleton (manager, monitor, path);
g_free (path);
}
static void
on_device_removed (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
GDBusObjectManagerServer *manager)
{
int device_id;
char *path;
device_id = clutter_input_device_get_device_id (device);
path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id);
g_dbus_object_manager_server_unexport (manager, path);
g_free (path);
g_clear_object (&device_monitors[device_id]);
if (device_id == device_id_max)
device_id_max--;
}
static void
on_bus_acquired (GDBusConnection *connection,
const char *name,
@@ -879,10 +901,19 @@ on_bus_acquired (GDBusConnection *connection,
{
GDBusObjectManagerServer *manager;
ClutterDeviceManager *device_manager;
MetaIdleMonitor *monitor;
GSList *devices, *iter;
char *path;
manager = g_dbus_object_manager_server_new ("/org/gnome/Mutter/IdleMonitor");
/* We never clear the core monitor, as that's supposed to cumulate idle times from
all devices */
monitor = meta_idle_monitor_get_core ();
path = g_strdup ("/org/gnome/Mutter/IdleMonitor/Core");
create_monitor_skeleton (manager, monitor, path);
g_free (path);
device_manager = clutter_device_manager_get_default ();
devices = clutter_device_manager_list_devices (device_manager);
@@ -891,8 +922,10 @@ on_bus_acquired (GDBusConnection *connection,
g_signal_connect_object (device_manager, "device-added",
G_CALLBACK (on_device_added), manager, 0);
g_signal_connect_object (device_manager, "device-removed",
G_CALLBACK (on_device_removed), manager, 0);
g_dbus_object_manager_server_set_connection (manager, g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL));
g_dbus_object_manager_server_set_connection (manager, connection);
}
static void
@@ -900,7 +933,7 @@ on_name_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
meta_topic (META_DEBUG_DBUS, "Acquired name %s\n", name);
meta_verbose ("Acquired name %s\n", name);
}
static void
@@ -908,7 +941,7 @@ on_name_lost (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s\n", name);
meta_verbose ("Lost or failed to acquire name %s\n", name);
}
void

View File

@@ -190,7 +190,7 @@ meta_monitor_config_init (MetaMonitorConfig *self)
filename = g_getenv ("MUTTER_MONITOR_FILENAME");
if (filename == NULL)
filename = "monitors-test.xml"; /* FIXME after testing */
filename = "monitors.xml";
path = g_build_filename (g_get_user_config_dir (), filename, NULL);
self->file = g_file_new_for_path (path);
@@ -952,8 +952,6 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
* or failing that, an output that is good to be a primary (LVDS or eDP,
* which are internal monitors), or failing that, the one with the
* best resolution
*
* Input assertions: there is at least one output
*/
static MetaOutput *
find_primary_output (MetaOutput *outputs,
@@ -963,6 +961,8 @@ find_primary_output (MetaOutput *outputs,
MetaOutput *best;
int best_width, best_height;
g_assert (n_outputs >= 1);
for (i = 0; i < n_outputs; i++)
{
if (outputs[i].is_primary)
@@ -1029,6 +1029,9 @@ make_default_config (MetaMonitorConfig *self,
In the latter case, search for a configuration that includes one
less screen, then add the new one as a presentation screen
in preferred mode.
XXX: but presentation mode is not implemented in the control-center
or in mutter core, so let's do extended for now.
*/
x = 0;
y = 0;
@@ -1054,7 +1057,7 @@ make_default_config (MetaMonitorConfig *self,
}
else if (j > i)
{
g_assert (output_key_equal (&ret->keys[i], &ref->keys[j - 1]));
g_assert (output_key_equal (&ret->keys[j], &ref->keys[j - 1]));
ret->outputs[j] = ref->outputs[j - 1];
x = MAX (x, ref->outputs[j - 1].rect.x + ref->outputs[j - 1].rect.width);
y = MAX (y, ref->outputs[j - 1].rect.y + ref->outputs[j - 1].rect.height);
@@ -1069,7 +1072,7 @@ make_default_config (MetaMonitorConfig *self,
ret->outputs[j].refresh_rate = outputs[0].preferred_mode->refresh_rate;
ret->outputs[j].transform = WL_OUTPUT_TRANSFORM_NORMAL;
ret->outputs[j].is_primary = FALSE;
ret->outputs[j].is_presentation = TRUE;
ret->outputs[j].is_presentation = FALSE;
}
}
@@ -1252,9 +1255,7 @@ meta_monitor_config_restore_previous (MetaMonitorConfig *self,
MetaMonitorManager *manager)
{
if (self->previous)
{
apply_configuration (self, self->previous, manager, FALSE);
}
apply_configuration (self, self->previous, manager, FALSE);
else
{
if (!meta_monitor_config_apply_stored (self, manager))
@@ -1543,7 +1544,7 @@ crtc_assignment_assign (CrtcAssignment *assign,
return TRUE;
}
else
{
{
MetaCRTCInfo *info = g_slice_new0 (MetaCRTCInfo);
info->crtc = crtc;
@@ -1555,7 +1556,7 @@ crtc_assignment_assign (CrtcAssignment *assign,
g_ptr_array_add (info->outputs, output);
g_hash_table_insert (assign->info, crtc, info);
return TRUE;
}
}
@@ -1653,15 +1654,28 @@ real_assign_crtcs (CrtcAssignment *assignment,
for (j = 0; j < n_modes; j++)
{
MetaMonitorMode *mode = &modes[j];
int width, height;
if (mode->width == output_config->rect.width &&
mode->height == output_config->rect.height &&
if (meta_monitor_transform_is_rotated (output_config->transform))
{
width = mode->height;
height = mode->width;
}
else
{
width = mode->width;
height = mode->height;
}
if (width == output_config->rect.width &&
height == output_config->rect.height &&
(pass == 1 || mode->refresh_rate == output_config->refresh_rate))
{
meta_verbose ("CRTC %ld: trying mode %dx%d@%fHz with output at %dx%d@%fHz (pass %d)\n",
meta_verbose ("CRTC %ld: trying mode %dx%d@%fHz with output at %dx%d@%fHz (transform %d) (pass %d)\n",
crtc->crtc_id,
mode->width, mode->height, mode->refresh_rate,
output_config->rect.width, output_config->rect.height, output_config->refresh_rate,
output_config->transform,
pass);

View File

@@ -1,767 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2013 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Author: Giovanni Campagna <gcampagn@redhat.com>
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <meta/main.h>
#include <meta/errors.h>
#include "monitor-private.h"
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
typedef struct {
drmModeConnector *connector;
unsigned n_encoders;
drmModeEncoderPtr *encoders;
drmModeEncoderPtr current_encoder;
/* bitmasks of encoder position in the resources array */
uint32_t encoder_mask;
uint32_t enc_clone_mask;
uint32_t dpms_prop_id;
} MetaOutputKms;
struct _MetaMonitorManagerKms
{
MetaMonitorManager parent_instance;
int fd;
drmModeConnector **connectors;
unsigned int n_connectors;
drmModeEncoder **encoders;
unsigned int n_encoders;
drmModeEncoder *current_encoder;
};
struct _MetaMonitorManagerKmsClass
{
MetaMonitorManagerClass parent_class;
};
G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
static int
compare_outputs (const void *one,
const void *two)
{
const MetaOutput *o_one = one, *o_two = two;
return strcmp (o_one->name, o_two->name);
}
static char *
make_output_name (drmModeConnector *connector)
{
static const char * const connector_type_names[] = {
"unknown", "VGA", "DVII", "DVID", "DVID", "Composite",
"SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort",
"HDMIA", "HDMIB", "TV", "eDP"
};
const char *connector_type_name;
if (connector->connector_type >= 0 &&
connector->connector_type < G_N_ELEMENTS (connector_type_names))
connector_type_name = connector_type_names[connector->connector_type];
else
connector_type_name = "unknown";
return g_strdup_printf ("%s%d", connector_type_name, connector->connector_id);
}
static void
meta_output_destroy_notify (MetaOutput *output)
{
MetaOutputKms *output_kms;
unsigned i;
output_kms = output->driver_private;
for (i = 0; i < output_kms->n_encoders; i++)
drmModeFreeEncoder (output_kms->encoders[i]);
g_slice_free (MetaOutputKms, output_kms);
}
static void
meta_monitor_mode_destroy_notify (MetaMonitorMode *output)
{
g_slice_free (drmModeModeInfo, output->driver_private);
}
static gboolean
drm_mode_equal (gconstpointer one,
gconstpointer two)
{
return memcmp (one, two, sizeof (drmModeModeInfo)) == 0;
}
static guint
drm_mode_hash (gconstpointer ptr)
{
const drmModeModeInfo *mode = ptr;
guint hash = 0;
hash ^= mode->clock;
hash ^= mode->hdisplay ^ mode->hsync_start ^ mode->hsync_end;
hash ^= mode->vdisplay ^ mode->vsync_start ^ mode->vsync_end;
hash ^= mode->vrefresh;
hash ^= mode->flags ^ mode->type;
return hash;
}
static void
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
drmModeRes *resources;
GHashTable *modes;
GHashTableIter iter;
drmModeModeInfo *mode;
unsigned int i, j, k;
unsigned int n_actual_outputs;
int width, height;
resources = drmModeGetResources(manager_kms->fd);
modes = g_hash_table_new (drm_mode_hash, drm_mode_equal);
manager->max_screen_width = resources->max_width;
manager->max_screen_height = resources->max_height;
manager->power_save_mode = META_POWER_SAVE_ON;
manager_kms->n_connectors = resources->count_connectors;
manager_kms->connectors = g_new (drmModeConnector *, manager_kms->n_connectors);
for (i = 0; i < manager_kms->n_connectors; i++)
{
drmModeConnector *connector;
connector = drmModeGetConnector (manager_kms->fd, resources->connectors[i]);
manager_kms->connectors[i] = connector;
if (connector->connection == DRM_MODE_CONNECTED)
{
/* Collect all modes for this connector */
for (j = 0; j < (unsigned)connector->count_modes; j++)
g_hash_table_add (modes, &connector->modes[j]);
}
}
manager_kms->n_encoders = resources->count_encoders;
manager_kms->encoders = g_new (drmModeEncoder *, manager_kms->n_encoders);
for (i = 0; i < manager_kms->n_encoders; i++)
{
manager_kms->encoders[i] = drmModeGetEncoder (manager_kms->fd,
resources->encoders[i]);
}
manager->n_modes = g_hash_table_size (modes);
manager->modes = g_new0 (MetaMonitorMode, manager->n_modes);
g_hash_table_iter_init (&iter, modes);
i = 0;
while (g_hash_table_iter_next (&iter, NULL, (gpointer)&mode))
{
MetaMonitorMode *meta_mode;
meta_mode = &manager->modes[i];
meta_mode->mode_id = i;
meta_mode->name = g_strndup (mode->name, DRM_DISPLAY_MODE_LEN);
meta_mode->width = mode->hdisplay;
meta_mode->height = mode->vdisplay;
meta_mode->refresh_rate = (1000 * mode->clock /
((float)mode->htotal * mode->vtotal));
meta_mode->driver_private = g_slice_dup (drmModeModeInfo, mode);
meta_mode->driver_notify = (GDestroyNotify)meta_monitor_mode_destroy_notify;
i++;
}
g_hash_table_destroy (modes);
manager->n_crtcs = resources->count_crtcs;
manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs);
width = 0; height = 0;
for (i = 0; i < (unsigned)resources->count_crtcs; i++)
{
drmModeCrtc *crtc;
MetaCRTC *meta_crtc;
crtc = drmModeGetCrtc (manager_kms->fd, resources->crtcs[i]);
meta_crtc = &manager->crtcs[i];
meta_crtc->crtc_id = crtc->crtc_id;
meta_crtc->rect.x = crtc->x;
meta_crtc->rect.y = crtc->y;
meta_crtc->rect.width = crtc->width;
meta_crtc->rect.height = crtc->height;
meta_crtc->dirty = FALSE;
/* FIXME: we can handle some transforms, with a combination of
scaling and fitting, but it is very driver dependent */
meta_crtc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
meta_crtc->all_transforms = 1 << WL_OUTPUT_TRANSFORM_NORMAL;
if (crtc->mode_valid)
{
for (j = 0; j < manager->n_modes; j++)
{
if (drm_mode_equal (&crtc->mode, manager->modes[j].driver_private))
{
meta_crtc->current_mode = &manager->modes[j];
break;
}
}
width = MAX (width, meta_crtc->rect.x + meta_crtc->rect.width);
height = MAX (height, meta_crtc->rect.y + meta_crtc->rect.height);
}
drmModeFreeCrtc (crtc);
}
manager->screen_width = width;
manager->screen_height = height;
manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
n_actual_outputs = 0;
for (i = 0; i < manager_kms->n_connectors; i++)
{
MetaOutput *meta_output;
MetaOutputKms *output_kms;
drmModeConnector *connector;
GArray *crtcs;
unsigned int crtc_mask;
connector = manager_kms->connectors[i];
meta_output = &manager->outputs[n_actual_outputs];
if (connector->connection == DRM_MODE_CONNECTED)
{
meta_output->output_id = connector->connector_id;
meta_output->name = make_output_name (connector);
meta_output->vendor = g_strdup ("unknown");
meta_output->product = g_strdup ("unknown");
meta_output->serial = g_strdup ("");
meta_output->width_mm = connector->mmWidth;
meta_output->height_mm = connector->mmHeight;
if (connector->subpixel == DRM_MODE_SUBPIXEL_UNKNOWN)
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
else if (connector->subpixel == DRM_MODE_SUBPIXEL_NONE)
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
else
meta_output->subpixel_order = connector->subpixel;
meta_output->n_modes = connector->count_modes;
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
for (j = 0; j < meta_output->n_modes; j++)
{
for (k = 0; k < manager->n_modes; k++)
{
if (drm_mode_equal (&connector->modes[j], manager->modes[k].driver_private))
{
meta_output->modes[j] = &manager->modes[k];
break;
}
}
}
meta_output->preferred_mode = meta_output->modes[0];
meta_output->driver_private = output_kms = g_slice_new0 (MetaOutputKms);
meta_output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
output_kms->connector = connector;
output_kms->n_encoders = connector->count_encoders;
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
crtc_mask = 0x7F;
for (j = 0; j < output_kms->n_encoders; j++)
{
output_kms->encoders[j] = drmModeGetEncoder (manager_kms->fd, connector->encoders[j]);
crtc_mask &= output_kms->encoders[j]->possible_crtcs;
if (output_kms->encoders[j]->encoder_id == connector->encoder_id)
output_kms->current_encoder = output_kms->encoders[j];
}
crtcs = g_array_new (FALSE, FALSE, sizeof (MetaCRTC*));
for (j = 0; j < manager->n_crtcs; j++)
{
if (crtc_mask & (1 << j))
{
MetaCRTC *crtc = &manager->crtcs[j];
g_array_append_val (crtcs, crtc);
}
}
meta_output->n_possible_crtcs = crtcs->len;
meta_output->possible_crtcs = (void*)g_array_free (crtcs, FALSE);
if (output_kms->current_encoder && output_kms->current_encoder->crtc_id != 0)
{
for (j = 0; j < manager->n_crtcs; j++)
{
if (manager->crtcs[j].crtc_id == output_kms->current_encoder->crtc_id)
{
meta_output->crtc = &manager->crtcs[j];
break;
}
}
}
else
meta_output->crtc = NULL;
meta_output->is_primary = FALSE;
meta_output->is_presentation = FALSE;
for (j = 0; j < (unsigned)connector->count_props; j++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty(manager_kms->fd, connector->props[j]);
if (prop)
{
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
strcmp(prop->name, "DPMS") == 0)
{
output_kms->dpms_prop_id = prop->prop_id;
drmModeFreeProperty(prop);
break;
}
drmModeFreeProperty(prop);
}
}
/* FIXME: backlight is a very driver specific thing unfortunately,
every DDX does its own thing, and the dumb KMS API does not include it.
For example, xf86-video-intel has a list of paths to probe in /sys/class/backlight
(one for each major HW maker, and then some).
We can't do the same because we're not root.
It might be best to leave backlight out of the story and rely on the setuid
helper in gnome-settings-daemon.
*/
meta_output->backlight_min = 0;
meta_output->backlight_max = 0;
meta_output->backlight = -1;
n_actual_outputs++;
}
}
manager->n_outputs = n_actual_outputs;
manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
/* Sort the outputs for easier handling in MetaMonitorConfig */
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
/* Now fix the clones.
Code mostly inspired by xf86-video-modesetting. */
/* XXX: intel hardware doesn't usually have clones, but we only have intel
cards, so this code was never tested! */
for (i = 0; i < manager->n_outputs; i++)
{
MetaOutput *meta_output;
MetaOutputKms *output_kms;
meta_output = &manager->outputs[i];
output_kms = meta_output->driver_private;
output_kms->enc_clone_mask = 0xff;
output_kms->encoder_mask = 0;
for (j = 0; j < output_kms->n_encoders; j++)
{
for (k = 0; k < manager_kms->n_encoders; k++)
{
if (output_kms->encoders[j]->encoder_id == manager_kms->encoders[k]->encoder_id)
{
output_kms->encoder_mask |= (1 << k);
break;
}
}
output_kms->enc_clone_mask &= output_kms->encoders[j]->possible_clones;
}
}
for (i = 0; i < manager->n_outputs; i++)
{
MetaOutput *meta_output;
MetaOutputKms *output_kms;
meta_output = &manager->outputs[i];
output_kms = meta_output->driver_private;
if (output_kms->enc_clone_mask == 0)
continue;
for (j = 0; j < manager->n_outputs; j++)
{
MetaOutput *meta_clone;
MetaOutputKms *clone_kms;
meta_clone = &manager->outputs[i];
clone_kms = meta_clone->driver_private;
if (meta_clone == meta_output)
continue;
if (clone_kms->encoder_mask == 0)
continue;
if (clone_kms->encoder_mask == output_kms->enc_clone_mask)
{
meta_output->n_possible_clones++;
meta_output->possible_clones = g_renew (MetaOutput *,
meta_output->possible_clones,
meta_output->n_possible_clones);
meta_output->possible_clones[meta_output->n_possible_clones - 1] = meta_clone;
}
}
}
drmModeFreeResources (resources);
}
static void
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
MetaPowerSave mode)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
uint64_t state;
unsigned i;
switch (mode) {
case META_POWER_SAVE_ON:
state = DRM_MODE_DPMS_ON;
break;
case META_POWER_SAVE_STANDBY:
state = DRM_MODE_DPMS_STANDBY;
break;
case META_POWER_SAVE_SUSPEND:
state = DRM_MODE_DPMS_SUSPEND;
break;
case META_POWER_SAVE_OFF:
state = DRM_MODE_DPMS_SUSPEND;
break;
default:
return;
}
for (i = 0; i < manager->n_outputs; i++)
{
MetaOutput *meta_output;
MetaOutputKms *output_kms;
meta_output = &manager->outputs[i];
output_kms = meta_output->driver_private;
if (output_kms->dpms_prop_id)
{
int ok = drmModeConnectorSetProperty(manager_kms->fd, meta_output->output_id,
output_kms->dpms_prop_id, state);
if (ok < 0)
meta_warning ("Failed to set power save mode for output %s: %s\n",
meta_output->name, strerror (errno));
}
}
}
static void
crtc_free (CoglKmsCrtc *crtc)
{
g_free (crtc->connectors);
g_slice_free (CoglKmsCrtc, crtc);
}
static void
meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
MetaCRTCInfo **crtcs,
unsigned int n_crtcs,
MetaOutputInfo **outputs,
unsigned int n_outputs)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
unsigned i;
GList *cogl_crtcs;
int width, height;
gboolean ok;
GError *error;
cogl_crtcs = NULL;
width = 0; height = 0;
for (i = 0; i < n_crtcs; i++)
{
MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
CoglKmsCrtc *cogl_crtc;
crtc->dirty = TRUE;
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
cogl_crtcs = g_list_prepend (cogl_crtcs, cogl_crtc);
if (crtc_info->mode == NULL)
{
cogl_crtc->id = crtc->crtc_id;
cogl_crtc->x = 0;
cogl_crtc->y = 0;
cogl_crtc->count = 0;
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
cogl_crtc->connectors = NULL;
cogl_crtc->count = 0;
crtc->rect.x = 0;
crtc->rect.y = 0;
crtc->rect.width = 0;
crtc->rect.height = 0;
crtc->current_mode = NULL;
}
else
{
MetaMonitorMode *mode;
uint32_t *outputs;
unsigned int j, n_outputs;
mode = crtc_info->mode;
cogl_crtc->id = crtc->crtc_id;
cogl_crtc->x = crtc_info->x;
cogl_crtc->y = crtc_info->y;
cogl_crtc->count = n_outputs = crtc_info->outputs->len;
cogl_crtc->connectors = outputs = g_new (uint32_t, n_outputs);
for (j = 0; j < n_outputs; j++)
{
MetaOutput *output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
outputs[j] = output->output_id;
output->dirty = TRUE;
output->crtc = crtc;
}
memcpy (&cogl_crtc->mode, crtc_info->mode->driver_private,
sizeof (drmModeModeInfo));
width = MAX (width, crtc_info->x + crtc_info->mode->width);
height = MAX (height, crtc_info->y + crtc_info->mode->height);
crtc->rect.x = crtc_info->x;
crtc->rect.y = crtc_info->y;
crtc->rect.width = mode->width;
crtc->rect.height = mode->height;
crtc->current_mode = mode;
crtc->transform = crtc_info->transform;
}
}
/* Disable CRTCs not mentioned in the list */
for (i = 0; i < manager->n_crtcs; i++)
{
MetaCRTC *crtc = &manager->crtcs[i];
CoglKmsCrtc *cogl_crtc;
crtc->logical_monitor = NULL;
if (crtc->dirty)
{
crtc->dirty = FALSE;
continue;
}
cogl_crtc = g_slice_new0 (CoglKmsCrtc);
cogl_crtcs = g_list_prepend (cogl_crtcs, cogl_crtc);
cogl_crtc->id = crtc->crtc_id;
cogl_crtc->x = 0;
cogl_crtc->y = 0;
cogl_crtc->count = 0;
memset (&cogl_crtc->mode, 0, sizeof (drmModeModeInfo));
cogl_crtc->connectors = NULL;
cogl_crtc->count = 0;
crtc->rect.x = 0;
crtc->rect.y = 0;
crtc->rect.width = 0;
crtc->rect.height = 0;
crtc->current_mode = NULL;
}
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
error = NULL;
ok = cogl_kms_display_set_layout (cogl_display, width, height, cogl_crtcs, &error);
g_list_free_full (cogl_crtcs, (GDestroyNotify) crtc_free);
if (!ok)
{
meta_warning ("Applying display configuration failed: %s\n", error->message);
g_error_free (error);
return;
}
for (i = 0; i < n_outputs; i++)
{
MetaOutputInfo *output_info = outputs[i];
MetaOutput *output = output_info->output;
output->is_primary = output_info->is_primary;
output->is_presentation = output_info->is_presentation;
}
/* Disable outputs not mentioned in the list */
for (i = 0; i < manager->n_outputs; i++)
{
MetaOutput *output = &manager->outputs[i];
if (output->dirty)
{
output->dirty = FALSE;
continue;
}
output->crtc = NULL;
output->is_primary = FALSE;
}
manager->screen_width = width;
manager->screen_height = height;
meta_monitor_manager_rebuild_derived (manager);
}
static void
meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager,
MetaCRTC *crtc,
gsize *size,
unsigned short **red,
unsigned short **green,
unsigned short **blue)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
drmModeCrtc *kms_crtc;
kms_crtc = drmModeGetCrtc (manager_kms->fd, crtc->crtc_id);
*size = kms_crtc->gamma_size;
*red = g_new (unsigned short, *size);
*green = g_new (unsigned short, *size);
*blue = g_new (unsigned short, *size);
drmModeCrtcGetGamma (manager_kms->fd, crtc->crtc_id, *size, *red, *green, *blue);
drmModeFreeCrtc (kms_crtc);
}
static void
meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager,
MetaCRTC *crtc,
gsize size,
unsigned short *red,
unsigned short *green,
unsigned short *blue)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
drmModeCrtcSetGamma (manager_kms->fd, crtc->crtc_id, size, red, green, blue);
}
static void
meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
CoglRenderer *cogl_renderer;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
cogl_renderer = cogl_display_get_renderer (cogl_display);
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
}
static void
meta_monitor_manager_kms_finalize (GObject *object)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
unsigned i;
for (i = 0; i < manager_kms->n_encoders; i++)
drmModeFreeEncoder (manager_kms->encoders[i]);
for (i = 0; i < manager_kms->n_connectors; i++)
drmModeFreeConnector (manager_kms->connectors[i]);
g_free (manager_kms->encoders);
g_free (manager_kms->connectors);
G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
}
static void
meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass)
{
MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_monitor_manager_kms_finalize;
manager_class->read_current = meta_monitor_manager_kms_read_current;
manager_class->apply_configuration = meta_monitor_manager_kms_apply_configuration;
manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode;
manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma;
manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma;
}

View File

@@ -38,6 +38,7 @@
#define META_MONITOR_PRIVATE_H
#include <cogl/cogl.h>
#include <libgnome-desktop/gnome-pnp-ids.h>
#include "display-private.h"
#include <meta/screen.h>
@@ -104,7 +105,7 @@ struct _MetaOutput
int backlight_max;
/* Used when changing configuration */
gboolean dirty;
gboolean is_dirty;
/* The low-level bits used to build the high-level info
in MetaMonitorInfo
@@ -115,9 +116,6 @@ struct _MetaOutput
*/
gboolean is_primary;
gboolean is_presentation;
gpointer driver_private;
GDestroyNotify driver_notify;
};
struct _MetaCRTC
@@ -134,21 +132,17 @@ struct _MetaCRTC
MetaMonitorInfo *logical_monitor;
/* Used when changing configuration */
gboolean dirty;
gboolean is_dirty;
};
struct _MetaMonitorMode
{
/* The low-level ID of this mode, used to apply back configuration */
glong mode_id;
char *name;
int width;
int height;
float refresh_rate;
gpointer driver_private;
GDestroyNotify driver_notify;
};
/**
@@ -171,8 +165,7 @@ struct _MetaMonitorInfo
gboolean in_fullscreen;
/* The primary or first output for this monitor, 0 if we can't figure out.
This is a XID when using XRandR, otherwise a KMS id (not implemented).
In any case, it can be matched to an output_id of a MetaOutput.
It can be matched to an output_id of a MetaOutput.
This is used as an opaque token on reconfiguration when switching from
clone to extened, to decide on what output the windows should go next
@@ -258,6 +251,8 @@ struct _MetaMonitorManager
int persistent_timeout_id;
MetaMonitorConfig *config;
GnomePnpIds *pnp_ids;
};
struct _MetaMonitorManagerClass
@@ -306,15 +301,6 @@ GType meta_monitor_manager_get_type (void);
void meta_monitor_manager_initialize (void);
MetaMonitorManager *meta_monitor_manager_get (void);
void meta_monitor_manager_init_dbus (MetaMonitorManager *manager,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean meta_monitor_manager_init_dbus_finish (MetaMonitorManager *manager,
GAsyncResult *result,
GError **error);
void meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager);
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
unsigned int *n_infos);
@@ -363,18 +349,6 @@ typedef struct _MetaMonitorManagerXrandr MetaMonitorManagerXrandr;
GType meta_monitor_manager_xrandr_get_type (void);
#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ())
#define META_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKms))
#define META_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
#define META_IS_MONITOR_MANAGER_KMS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER_KMS))
#define META_IS_MONITOR_MANAGER_KMS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER_KMS))
#define META_MONITOR_MANAGER_KMS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER_KMS, MetaMonitorManagerKmsClass))
typedef struct _MetaMonitorManagerKmsClass MetaMonitorManagerKmsClass;
typedef struct _MetaMonitorManagerKms MetaMonitorManagerKms;
GType meta_monitor_manager_kms_get_type (void);
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
@@ -405,4 +379,12 @@ void meta_monitor_config_restore_previous (MetaMonitorConfig *con
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */
static inline gboolean
meta_monitor_transform_is_rotated (enum wl_output_transform transform)
{
return (transform % 2);
}
#endif

View File

@@ -29,6 +29,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <clutter/clutter.h>
#include <X11/Xatom.h>
@@ -39,8 +40,15 @@
#include <meta/errors.h>
#include "monitor-private.h"
#include "edid.h"
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
/* Look for DPI_FALLBACK in:
* http://git.gnome.org/browse/gnome-settings-daemon/tree/plugins/xsettings/gsd-xsettings-manager.c
* for the reasoning */
#define DPI_FALLBACK 96.0
struct _MetaMonitorManagerXrandr
{
MetaMonitorManager parent_instance;
@@ -162,8 +170,8 @@ static int
normalize_backlight (MetaOutput *output,
int hw_value)
{
return round((double)(hw_value - output->backlight_min) /
(output->backlight_max - output->backlight_min) * 100.0);
return round ((double)(hw_value - output->backlight_min) /
(output->backlight_max - output->backlight_min) * 100.0);
}
static int
@@ -235,6 +243,74 @@ compare_outputs (const void *one,
return strcmp (o_one->name, o_two->name);
}
static guint8 *
get_edid_property (Display *dpy,
RROutput output,
Atom atom,
gsize *len)
{
unsigned char *prop;
int actual_format;
unsigned long nitems, bytes_after;
Atom actual_type;
guint8 *result;
XRRGetOutputProperty (dpy, output, atom,
0, 100, False, False,
AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &prop);
if (actual_type == XA_INTEGER && actual_format == 8)
{
result = g_memdup (prop, nitems);
if (len)
*len = nitems;
}
else
{
result = NULL;
}
XFree (prop);
return result;
}
static GBytes *
read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
XID output_id)
{
Atom edid_atom;
guint8 *result;
gsize len;
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE);
result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len);
if (!result)
{
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE);
result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len);
}
if (!result)
{
edid_atom = XInternAtom (manager_xrandr->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE);
result = get_edid_property (manager_xrandr->xdisplay, output_id, edid_atom, &len);
}
if (result)
{
if (len > 0 && len % 128 == 0)
return g_bytes_new_take (result, len);
else
g_free (result);
}
return NULL;
}
static void
meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
{
@@ -261,18 +337,23 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
dpms_enabled)
{
switch (dpms_state)
{
case DPMSModeOn:
manager->power_save_mode = META_POWER_SAVE_ON;
case DPMSModeStandby:
manager->power_save_mode = META_POWER_SAVE_STANDBY;
case DPMSModeSuspend:
manager->power_save_mode = META_POWER_SAVE_SUSPEND;
case DPMSModeOff:
manager->power_save_mode = META_POWER_SAVE_OFF;
default:
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
}
{
case DPMSModeOn:
manager->power_save_mode = META_POWER_SAVE_ON;
break;
case DPMSModeStandby:
manager->power_save_mode = META_POWER_SAVE_STANDBY;
break;
case DPMSModeSuspend:
manager->power_save_mode = META_POWER_SAVE_SUSPEND;
break;
case DPMSModeOff:
manager->power_save_mode = META_POWER_SAVE_OFF;
break;
default:
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
break;
}
}
else
{
@@ -333,7 +414,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
meta_crtc->rect.y = crtc->y;
meta_crtc->rect.width = crtc->width;
meta_crtc->rect.height = crtc->height;
meta_crtc->dirty = FALSE;
meta_crtc->is_dirty = FALSE;
meta_crtc->transform = wl_transform_from_xrandr (crtc->rotation);
meta_crtc->all_transforms = wl_transform_from_xrandr_all (crtc->rotations);
@@ -364,11 +445,42 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
if (output->connection != RR_Disconnected)
{
GBytes *edid;
MonitorInfo *parsed_edid;
meta_output->output_id = resources->outputs[i];
meta_output->name = g_strdup (output->name);
meta_output->vendor = g_strdup ("unknown");
meta_output->product = g_strdup ("unknown");
meta_output->serial = g_strdup ("");
edid = read_output_edid (manager_xrandr, meta_output->output_id);
if (edid)
{
gsize len;
parsed_edid = decode_edid (g_bytes_get_data (edid, &len));
if (parsed_edid)
{
meta_output->vendor = g_strndup (parsed_edid->manufacturer_code, 4);
if (parsed_edid->dsc_product_name[0])
meta_output->product = g_strndup (parsed_edid->dsc_product_name, 14);
else
meta_output->product = g_strdup_printf ("0x%04x", (unsigned)parsed_edid->product_code);
if (parsed_edid->dsc_serial_number[0])
meta_output->serial = g_strndup (parsed_edid->dsc_serial_number, 14);
else
meta_output->serial = g_strdup_printf ("0x%08x", parsed_edid->serial_number);
g_free (parsed_edid);
}
g_bytes_unref (edid);
}
if (!meta_output->vendor)
{
meta_output->vendor = g_strdup ("unknown");
meta_output->product = g_strdup ("unknown");
meta_output->serial = g_strdup ("unknown");
}
meta_output->width_mm = output->mm_width;
meta_output->height_mm = output->mm_height;
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
@@ -420,7 +532,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
*/
for (j = 0; j < (unsigned)output->nclone; j++)
{
meta_output->possible_clones = GINT_TO_POINTER (output->clones[j]);
meta_output->possible_clones[j] = GINT_TO_POINTER (output->clones[j]);
}
meta_output->is_primary = ((XID)meta_output->output_id == primary_output);
@@ -466,73 +578,13 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
}
}
static guint8 *
get_edid_property (Display *dpy,
RROutput output,
Atom atom,
gsize *len)
{
unsigned char *prop;
int actual_format;
unsigned long nitems, bytes_after;
Atom actual_type;
guint8 *result;
XRRGetOutputProperty (dpy, output, atom,
0, 100, False, False,
AnyPropertyType,
&actual_type, &actual_format,
&nitems, &bytes_after, &prop);
if (actual_type == XA_INTEGER && actual_format == 8)
{
result = g_memdup (prop, nitems);
if (len)
*len = nitems;
}
else
{
result = NULL;
}
XFree (prop);
return result;
}
static GBytes *
meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager,
MetaOutput *output)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
Atom edid_atom;
guint8 *result;
gsize len;
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE);
result = get_edid_property (manager_xrandr->xdisplay, output->output_id, edid_atom, &len);
if (!result)
{
edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE);
result = get_edid_property (manager_xrandr->xdisplay, output->output_id, edid_atom, &len);
}
if (!result)
{
edid_atom = XInternAtom (manager_xrandr->xdisplay, "XFree86_DDC_EDID1_RAWDATA", FALSE);
result = get_edid_property (manager_xrandr->xdisplay, output->output_id, edid_atom, &len);
}
if (result)
{
if (len > 0 && len % 128 == 0)
return g_bytes_new_take (result, len);
else
g_free (result);
}
return NULL;
return read_output_edid (manager_xrandr, output->output_id);
}
static void
@@ -615,16 +667,46 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
unsigned i;
int width, height, width_mm, height_mm;
meta_display_grab (meta_get_display ());
/* First compute the new size of the screen (framebuffer) */
width = 0; height = 0;
for (i = 0; i < n_crtcs; i++)
{
MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
crtc->dirty = TRUE;
crtc->is_dirty = TRUE;
if (crtc_info->mode == NULL)
continue;
if (meta_monitor_transform_is_rotated (crtc_info->transform))
{
width = MAX (width, crtc_info->x + crtc_info->mode->height);
height = MAX (height, crtc_info->y + crtc_info->mode->width);
}
else
{
width = MAX (width, crtc_info->x + crtc_info->mode->width);
height = MAX (height, crtc_info->y + crtc_info->mode->height);
}
}
/* Second disable all newly disabled CRTCs, or CRTCs that in the previous
configuration would be outside the new framebuffer (otherwise X complains
loudly when resizing)
CRTC will be enabled again after resizing the FB
*/
for (i = 0; i < n_crtcs; i++)
{
MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
if (crtc_info->mode == NULL ||
crtc->rect.x + crtc->rect.width > width ||
crtc->rect.y + crtc->rect.height > height)
{
XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
@@ -634,57 +716,13 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
None,
RR_Rotate_0,
NULL, 0);
crtc->rect.x = 0;
crtc->rect.y = 0;
crtc->rect.width = 0;
crtc->rect.height = 0;
crtc->current_mode = NULL;
}
else
{
MetaMonitorMode *mode;
XID *outputs;
int j, n_outputs;
Status ok;
mode = crtc_info->mode;
n_outputs = crtc_info->outputs->len;
outputs = g_new (XID, n_outputs);
for (j = 0; j < n_outputs; j++)
outputs[j] = ((MetaOutput**)crtc_info->outputs->pdata)[j]->output_id;
meta_error_trap_push (meta_get_display ());
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
manager_xrandr->time,
crtc_info->x, crtc_info->y,
(XID)mode->mode_id,
wl_transform_to_xrandr (crtc_info->transform),
outputs, n_outputs);
meta_error_trap_pop (meta_get_display ());
if (ok != Success)
meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n",
(unsigned)(crtc - manager->crtcs), (unsigned)(mode - manager->modes),
mode->width, mode->height, (float)mode->refresh_rate,
crtc_info->x, crtc_info->y, crtc_info->transform);
g_free (outputs);
}
}
for (i = 0; i < n_outputs; i++)
{
MetaOutputInfo *output_info = outputs[i];
if (output_info->is_primary)
{
XRRSetOutputPrimary (manager_xrandr->xdisplay,
DefaultRootWindow (manager_xrandr->xdisplay),
(XID)output_info->output->output_id);
}
output_set_presentation_xrandr (manager_xrandr,
output_info->output,
output_info->is_presentation);
}
/* Disable CRTCs not mentioned in the list */
@@ -692,9 +730,9 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
{
MetaCRTC *crtc = &manager->crtcs[i];
if (crtc->dirty)
if (crtc->is_dirty)
{
crtc->dirty = FALSE;
crtc->is_dirty = FALSE;
continue;
}
if (crtc->current_mode == NULL)
@@ -708,6 +746,159 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
None,
RR_Rotate_0,
NULL, 0);
crtc->rect.x = 0;
crtc->rect.y = 0;
crtc->rect.width = 0;
crtc->rect.height = 0;
crtc->current_mode = NULL;
}
g_assert (width > 0 && height > 0);
/* The 'physical size' of an X screen is meaningless if that screen
* can consist of many monitors. So just pick a size that make the
* dpi 96.
*
* Firefox and Evince apparently believe what X tells them.
*/
width_mm = (width / DPI_FALLBACK) * 25.4 + 0.5;
height_mm = (height / DPI_FALLBACK) * 25.4 + 0.5;
meta_error_trap_push (meta_get_display ());
XRRSetScreenSize (manager_xrandr->xdisplay, DefaultRootWindow (manager_xrandr->xdisplay),
width, height, width_mm, height_mm);
meta_error_trap_pop (meta_get_display ());
for (i = 0; i < n_crtcs; i++)
{
MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
if (crtc_info->mode != NULL)
{
MetaMonitorMode *mode;
XID *outputs;
unsigned int j, n_outputs;
int width, height;
Status ok;
unsigned long old_controlled_mask;
unsigned long new_controlled_mask;
mode = crtc_info->mode;
n_outputs = crtc_info->outputs->len;
outputs = g_new (XID, n_outputs);
old_controlled_mask = 0;
for (j = 0; j < manager->n_outputs; j++)
{
MetaOutput *output;
output = &manager->outputs[j];
if (output->crtc == crtc)
old_controlled_mask |= 1UL << j;
}
new_controlled_mask = 0;
for (j = 0; j < n_outputs; j++)
{
MetaOutput *output;
output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
output->is_dirty = TRUE;
output->crtc = crtc;
new_controlled_mask |= 1UL << j;
outputs[j] = output->output_id;
}
if (crtc->current_mode == mode &&
crtc->rect.x == crtc_info->x &&
crtc->rect.y == crtc_info->y &&
crtc->transform == crtc_info->transform &&
old_controlled_mask == new_controlled_mask)
{
/* No change */
goto next;
}
meta_error_trap_push (meta_get_display ());
ok = XRRSetCrtcConfig (manager_xrandr->xdisplay,
manager_xrandr->resources,
(XID)crtc->crtc_id,
manager_xrandr->time,
crtc_info->x, crtc_info->y,
(XID)mode->mode_id,
wl_transform_to_xrandr (crtc_info->transform),
outputs, n_outputs);
meta_error_trap_pop (meta_get_display ());
if (ok != Success)
{
meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n",
(unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id),
mode->width, mode->height, (float)mode->refresh_rate,
crtc_info->x, crtc_info->y, crtc_info->transform);
goto next;
}
if (meta_monitor_transform_is_rotated (crtc_info->transform))
{
width = mode->height;
height = mode->width;
}
else
{
width = mode->width;
height = mode->height;
}
crtc->rect.x = crtc_info->x;
crtc->rect.y = crtc_info->y;
crtc->rect.width = width;
crtc->rect.height = height;
crtc->current_mode = mode;
crtc->transform = crtc_info->transform;
next:
g_free (outputs);
}
}
for (i = 0; i < n_outputs; i++)
{
MetaOutputInfo *output_info = outputs[i];
MetaOutput *output = output_info->output;
if (output_info->is_primary)
{
XRRSetOutputPrimary (manager_xrandr->xdisplay,
DefaultRootWindow (manager_xrandr->xdisplay),
(XID)output_info->output->output_id);
}
output_set_presentation_xrandr (manager_xrandr,
output_info->output,
output_info->is_presentation);
output->is_primary = output_info->is_primary;
output->is_presentation = output_info->is_presentation;
}
/* Disable outputs not mentioned in the list */
for (i = 0; i < manager->n_outputs; i++)
{
MetaOutput *output = &manager->outputs[i];
if (output->is_dirty)
{
output->is_dirty = FALSE;
continue;
}
output->crtc = NULL;
output->is_primary = FALSE;
}
meta_display_ungrab (meta_get_display ());
@@ -722,7 +913,7 @@ meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager,
MetaDisplay *display = meta_get_display ();
int hw_value;
hw_value = round((double)value / 100.0 * output->backlight_max + output->backlight_min);
hw_value = round ((double)value / 100.0 * output->backlight_max + output->backlight_min);
meta_error_trap_push (display);
XRRChangeOutputProperty (manager_xrandr->xdisplay,
@@ -766,14 +957,16 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
unsigned short *blue)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
XRRCrtcGamma gamma;
XRRCrtcGamma *gamma;
gamma.size = size;
gamma.red = red;
gamma.green = green;
gamma.blue = blue;
gamma = XRRAllocGamma (size);
memcpy (gamma->red, red, sizeof (unsigned short) * size);
memcpy (gamma->green, green, sizeof (unsigned short) * size);
memcpy (gamma->blue, blue, sizeof (unsigned short) * size);
XRRSetCrtcGamma (manager_xrandr->xdisplay, (XID)crtc->crtc_id, &gamma);
XRRSetCrtcGamma (manager_xrandr->xdisplay, (XID)crtc->crtc_id, gamma);
XRRFreeGamma (gamma);
}
static gboolean

View File

@@ -1,4 +1,4 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2001, 2002 Havoc Pennington
@@ -28,20 +28,20 @@
#include "config.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <meta/main.h>
#include <meta/util.h>
#include <meta/errors.h>
#include "monitor-private.h"
#include "meta-wayland-private.h"
#include "meta-dbus-xrandr.h"
#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1)
enum {
MONITORS_CHANGED,
CONFIRM_DISPLAY_CHANGE,
SIGNALS_LAST
};
@@ -61,8 +61,8 @@ G_DEFINE_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYP
static void free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
static void free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes);
static void invalidate_logical_config (MetaMonitorManager *manager);
static void initialize_dbus_interface (MetaMonitorManager *manager);
static void
read_current_dummy (MetaMonitorManager *manager)
@@ -127,7 +127,7 @@ read_current_dummy (MetaMonitorManager *manager)
manager->crtcs[0].current_mode = &manager->modes[0];
manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS;
manager->crtcs[0].dirty = FALSE;
manager->crtcs[0].is_dirty = FALSE;
manager->crtcs[0].logical_monitor = NULL;
manager->crtcs[1].crtc_id = 5;
@@ -138,7 +138,7 @@ read_current_dummy (MetaMonitorManager *manager)
manager->crtcs[1].current_mode = NULL;
manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL;
manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS;
manager->crtcs[1].dirty = FALSE;
manager->crtcs[1].is_dirty = FALSE;
manager->crtcs[1].logical_monitor = NULL;
manager->crtcs[2].crtc_id = 5;
@@ -149,7 +149,7 @@ read_current_dummy (MetaMonitorManager *manager)
manager->crtcs[2].current_mode = NULL;
manager->crtcs[2].transform = WL_OUTPUT_TRANSFORM_NORMAL;
manager->crtcs[2].all_transforms = ALL_WL_TRANSFORMS;
manager->crtcs[2].dirty = FALSE;
manager->crtcs[2].is_dirty = FALSE;
manager->crtcs[2].logical_monitor = NULL;
manager->outputs = g_new0 (MetaOutput, 3);
@@ -251,7 +251,7 @@ apply_config_dummy (MetaMonitorManager *manager,
{
MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
crtc->dirty = TRUE;
crtc->is_dirty = TRUE;
if (crtc_info->mode == NULL)
{
@@ -266,25 +266,37 @@ apply_config_dummy (MetaMonitorManager *manager,
MetaMonitorMode *mode;
MetaOutput *output;
int i, n_outputs;
int width, height;
mode = crtc_info->mode;
if (meta_monitor_transform_is_rotated (crtc_info->transform))
{
width = mode->height;
height = mode->width;
}
else
{
width = mode->width;
height = mode->height;
}
crtc->rect.x = crtc_info->x;
crtc->rect.y = crtc_info->y;
crtc->rect.width = mode->width;
crtc->rect.height = mode->height;
crtc->rect.width = width;
crtc->rect.height = height;
crtc->current_mode = mode;
crtc->transform = crtc_info->transform;
screen_width = MAX (screen_width, crtc_info->x + mode->width);
screen_height = MAX (screen_height, crtc_info->y + mode->height);
screen_width = MAX (screen_width, crtc_info->x + width);
screen_height = MAX (screen_height, crtc_info->y + height);
n_outputs = crtc_info->outputs->len;
for (i = 0; i < n_outputs; i++)
{
output = ((MetaOutput**)crtc_info->outputs->pdata)[i];
output->dirty = TRUE;
output->is_dirty = TRUE;
output->crtc = crtc;
}
}
@@ -306,9 +318,9 @@ apply_config_dummy (MetaMonitorManager *manager,
crtc->logical_monitor = NULL;
if (crtc->dirty)
if (crtc->is_dirty)
{
crtc->dirty = FALSE;
crtc->is_dirty = FALSE;
continue;
}
@@ -324,9 +336,9 @@ apply_config_dummy (MetaMonitorManager *manager,
{
MetaOutput *output = &manager->outputs[i];
if (output->dirty)
if (output->is_dirty)
{
output->dirty = FALSE;
output->is_dirty = FALSE;
continue;
}
@@ -337,7 +349,7 @@ apply_config_dummy (MetaMonitorManager *manager,
manager->screen_width = screen_width;
manager->screen_height = screen_height;
meta_monitor_manager_rebuild_derived (manager);
invalidate_logical_config (manager);
}
static GBytes *
@@ -462,6 +474,15 @@ make_logical_config (MetaMonitorManager *manager)
manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
}
static GType
get_default_backend (void)
{
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER; /* FIXME: KMS */
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
static MetaMonitorManager *
meta_monitor_manager_new (void)
{
@@ -471,21 +492,7 @@ meta_monitor_manager_new (void)
env = g_getenv ("META_DEBUG_MULTIMONITOR");
if (env == NULL)
{
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
if (meta_wayland_compositor_is_native (compositor))
type = META_TYPE_MONITOR_MANAGER_KMS;
else
type = META_TYPE_MONITOR_MANAGER;
}
else
type = META_TYPE_MONITOR_MANAGER_XRANDR;
}
type = get_default_backend ();
else if (strcmp (env, "xrandr") == 0)
type = META_TYPE_MONITOR_MANAGER_XRANDR;
else
@@ -520,22 +527,22 @@ meta_monitor_manager_constructed (GObject *object)
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
int n_old_outputs;
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
free_output_array (old_outputs, n_old_outputs);
free_mode_array (old_modes, n_old_modes);
g_free (old_modes);
g_free (old_crtcs);
}
make_logical_config (manager);
initialize_dbus_interface (manager);
manager->in_init = FALSE;
}
@@ -575,39 +582,19 @@ free_output_array (MetaOutput *old_outputs,
g_free (old_outputs[i].modes);
g_free (old_outputs[i].possible_crtcs);
g_free (old_outputs[i].possible_clones);
if (old_outputs[i].driver_notify)
old_outputs[i].driver_notify (&old_outputs[i]);
}
g_free (old_outputs);
}
static void
free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes)
{
int i;
for (i = 0; i < n_old_modes; i++)
{
g_free (old_modes[i].name);
if (old_modes[i].driver_notify)
old_modes[i].driver_notify (&old_modes[i]);
}
g_free (old_modes);
}
static void
meta_monitor_manager_finalize (GObject *object)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
free_output_array (manager->outputs, manager->n_outputs);
free_mode_array (manager->modes, manager->n_modes);
g_free (manager->monitor_infos);
g_free (manager->modes);
g_free (manager->crtcs);
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
@@ -677,17 +664,9 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
object_class->finalize = meta_monitor_manager_finalize;
klass->read_current = read_current_dummy;
klass->read_edid = read_edid_dummy;
klass->get_edid_file = get_edid_file_dummy;
klass->apply_configuration = apply_config_dummy;
signals[MONITORS_CHANGED] =
g_signal_new ("monitors-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
klass->get_edid_file = get_edid_file_dummy;
klass->read_edid = read_edid_dummy;
signals[CONFIRM_DISPLAY_CHANGE] =
g_signal_new ("confirm-display-change",
@@ -724,16 +703,41 @@ diagonal_to_str (double d)
}
static char *
make_display_name (MetaOutput *output)
make_display_name (MetaMonitorManager *manager,
MetaOutput *output)
{
if (g_str_has_prefix (output->name, "LVDS") ||
g_str_has_prefix (output->name, "eDP"))
return g_strdup (_("Built-in display"));
if (output->width_mm != -1 && output->height_mm != -1)
{
double d = sqrt (output->width_mm * output->width_mm +
output->height_mm * output->height_mm);
char *inches = diagonal_to_str (d / 25.4);
char *vendor_name;
char *ret;
ret = g_strdup_printf ("%s %s", output->vendor, inches);
if (g_strcmp0 (output->vendor, "unknown") != 0)
{
if (!manager->pnp_ids)
manager->pnp_ids = gnome_pnp_ids_new ();
vendor_name = gnome_pnp_ids_get_pnp_id (manager->pnp_ids,
output->vendor);
ret = g_strdup_printf ("%s %s", vendor_name, inches);
g_free (vendor_name);
}
else
{
/* TRANSLATORS: this is a monitor name (in case we don't know
the vendor), it's Unknown followed by a size in inches,
like 'Unknown 15"'
*/
ret = g_strdup_printf (_("Unknown %s"), inches);
}
g_free (inches);
return ret;
@@ -809,8 +813,12 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
g_variant_new_string (output->product));
g_variant_builder_add (&properties, "{sv}", "serial",
g_variant_new_string (output->serial));
g_variant_builder_add (&properties, "{sv}", "width-mm",
g_variant_new_int32 (output->width_mm));
g_variant_builder_add (&properties, "{sv}", "height-mm",
g_variant_new_int32 (output->height_mm));
g_variant_builder_add (&properties, "{sv}", "display-name",
g_variant_new_take_string (make_display_name (output)));
g_variant_new_take_string (make_display_name (manager, output)));
g_variant_builder_add (&properties, "{sv}", "backlight",
g_variant_new_int32 (output->backlight));
g_variant_builder_add (&properties, "{sv}", "primary",
@@ -978,7 +986,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
crtc_info = g_slice_new (MetaCRTCInfo);
crtc_info->outputs = g_ptr_array_new ();
if (crtc_id < 0 || crtc_id >= manager->n_crtcs)
if (crtc_id >= manager->n_crtcs)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1000,10 +1008,23 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
if (mode)
{
int width, height;
if (meta_monitor_transform_is_rotated (transform))
{
width = mode->height;
height = mode->width;
}
else
{
width = mode->width;
height = mode->height;
}
if (x < 0 ||
x + mode->width > manager->max_screen_width ||
x + width > manager->max_screen_width ||
y < 0 ||
y + mode->height > manager->max_screen_height)
y + height > manager->max_screen_height)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1011,8 +1032,8 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE;
}
new_screen_width = MAX (new_screen_width, x + mode->width);
new_screen_height = MAX (new_screen_height, y + mode->height);
new_screen_width = MAX (new_screen_width, x + width);
new_screen_height = MAX (new_screen_height, y + height);
crtc_info->x = x;
crtc_info->y = y;
}
@@ -1023,7 +1044,8 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
}
if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
transform > WL_OUTPUT_TRANSFORM_FLIPPED_270)
transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 ||
((crtc->all_transforms & (1 << transform)) == 0))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1037,7 +1059,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
{
MetaOutput *output;
if (output_id < 0 || output_id >= manager->n_outputs)
if (output_id >= manager->n_outputs)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1094,7 +1116,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
MetaOutputInfo *output_info;
gboolean primary, presentation;
if (output_id < 0 || output_id >= manager->n_outputs)
if (output_id >= manager->n_outputs)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1187,7 +1209,7 @@ meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
return TRUE;
}
if (output_id < 0 || output_id >= manager->n_outputs)
if (output_id >= manager->n_outputs)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1215,7 +1237,7 @@ meta_monitor_manager_handle_change_backlight (MetaDBusDisplayConfig *skeleton,
META_MONITOR_MANAGER_GET_CLASS (manager)->change_backlight (manager, output, value);
meta_dbus_display_config_complete_change_backlight (skeleton, invocation);
meta_dbus_display_config_complete_change_backlight (skeleton, invocation, output->backlight);
return TRUE;
}
@@ -1243,7 +1265,7 @@ meta_monitor_manager_handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton,
return TRUE;
}
if (crtc_id < 0 || crtc_id >= manager->n_crtcs)
if (crtc_id >= manager->n_crtcs)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1305,7 +1327,7 @@ meta_monitor_manager_handle_set_crtc_gamma (MetaDBusDisplayConfig *skeleton,
return TRUE;
}
if (crtc_id < 0 || crtc_id >= manager->n_crtcs)
if (crtc_id >= manager->n_crtcs)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
@@ -1351,8 +1373,7 @@ on_bus_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
GTask *task = user_data;
MetaMonitorManager *manager = g_task_get_task_data (task);
MetaMonitorManager *manager = user_data;
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager),
connection,
@@ -1365,11 +1386,7 @@ on_name_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
GTask *task = user_data;
meta_topic (META_DEBUG_DBUS, "Acquired name %s\n", name);
g_task_return_boolean (task, TRUE);
}
static void
@@ -1380,14 +1397,9 @@ on_name_lost (GDBusConnection *connection,
meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s\n", name);
}
void
meta_monitor_manager_init_dbus (MetaMonitorManager *manager,
GAsyncReadyCallback callback,
gpointer user_data)
static void
initialize_dbus_interface (MetaMonitorManager *manager)
{
GTask *task = g_task_new (manager, NULL, callback, user_data);
g_task_set_task_data (task, g_object_ref (manager), g_object_unref);
manager->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
"org.gnome.Mutter.DisplayConfig",
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
@@ -1396,32 +1408,24 @@ meta_monitor_manager_init_dbus (MetaMonitorManager *manager,
on_bus_acquired,
on_name_acquired,
on_name_lost,
task,
g_object_ref (manager),
g_object_unref);
}
gboolean
meta_monitor_manager_init_dbus_finish (MetaMonitorManager *manager,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}
static MetaMonitorManager *global_manager;
static MetaMonitorManager *global_monitor_manager;
void
meta_monitor_manager_initialize (void)
{
global_manager = meta_monitor_manager_new ();
global_monitor_manager = meta_monitor_manager_new ();
}
MetaMonitorManager *
meta_monitor_manager_get (void)
{
g_assert (global_manager != NULL);
g_assert (global_monitor_manager != NULL);
return global_manager;
return global_monitor_manager;
}
MetaMonitorInfo *
@@ -1481,8 +1485,8 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
*height = manager->max_screen_height;
}
void
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
static void
invalidate_logical_config (MetaMonitorManager *manager)
{
MetaMonitorInfo *old_monitor_infos;
@@ -1493,7 +1497,7 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
make_logical_config (manager);
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
g_signal_emit_by_name (manager, "monitors-changed");
g_free (old_monitor_infos);
}
@@ -1506,7 +1510,7 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
int n_old_outputs;
gboolean changed;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
@@ -1522,7 +1526,6 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
@@ -1537,7 +1540,7 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
*/
if (meta_monitor_config_match_current (manager->config, manager))
{
meta_monitor_manager_rebuild_derived (manager);
invalidate_logical_config (manager);
}
else
{
@@ -1546,7 +1549,7 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
}
free_output_array (old_outputs, n_old_outputs);
free_mode_array (old_modes, n_old_modes);
g_free (old_modes);
g_free (old_crtcs);
return TRUE;

View File

@@ -247,12 +247,12 @@ void meta_screen_set_active_workspace_hint (MetaScreen *screen);
Window meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
gboolean meta_screen_handle_xevent (MetaScreen *screen,
XEvent *xevent);
int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
int index);
int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
int index);
gboolean meta_screen_handle_xevent (MetaScreen *screen,
XEvent *xevent);
#endif

View File

@@ -45,11 +45,8 @@
#include <meta/compositor.h>
#include "mutter-enum-types.h"
#include "core.h"
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
#include "meta-cursor-tracker-private.h"
#include "meta-idle-monitor-private.h"
#include <X11/extensions/Xinerama.h>
@@ -677,10 +674,8 @@ meta_screen_new (MetaDisplay *display,
screen->xscreen = ScreenOfDisplay (xdisplay, number);
screen->xroot = xroot;
screen->rect.x = screen->rect.y = 0;
#ifdef HAVE_WAYLAND
if (!meta_is_wayland_compositor ())
#endif
meta_monitor_manager_initialize ();
manager = meta_monitor_manager_get ();
@@ -691,12 +686,6 @@ meta_screen_new (MetaDisplay *display,
&screen->rect.width,
&screen->rect.height);
#ifdef HAVE_WAYLAND
if (!meta_is_wayland_compositor ())
#endif
meta_monitor_manager_init_dbus (manager, NULL, NULL);
meta_idle_monitor_init_dbus ();
screen->current_cursor = -1; /* invalid/unset */
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
@@ -722,8 +711,8 @@ meta_screen_new (MetaDisplay *display,
screen->guard_window = None;
reload_monitor_infos (screen);
meta_cursor_tracker_get_for_screen (screen);
meta_cursor_tracker_get_for_screen (screen);
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
/* Handle creating a no_focus_window for this screen */
@@ -2884,9 +2873,10 @@ on_monitors_changed (MetaMonitorManager *manager,
&changes);
}
meta_compositor_sync_screen_size (screen->display->compositor,
screen,
screen->rect.width, screen->rect.height);
if (screen->display->compositor)
meta_compositor_sync_screen_size (screen->display->compositor,
screen,
screen->rect.width, screen->rect.height);
/* Queue a resize on all the windows */
meta_screen_foreach_window (screen, meta_screen_resize_func, 0);

View File

@@ -44,9 +44,7 @@
#include <X11/Xutil.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
/* XXX: We should find a nicer approach to deal with the
* circular dependency we have with the current headers

View File

@@ -62,9 +62,7 @@
#include <X11/extensions/Xcomposite.h>
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
/* Windows that unmaximize to a size bigger than that fraction of the workarea
* will be scaled down to that size (while maintaining aspect ratio).
@@ -853,9 +851,7 @@ meta_window_new_shared (MetaDisplay *display,
window->dialog_pid = -1;
window->client_type = client_type;
#ifdef HAVE_WAYLAND
window->surface = surface;
#endif
window->xwindow = xwindow;
/* this is in window->screen->display, but that's too annoying to
@@ -1375,7 +1371,6 @@ display_notify_window (MetaDisplay *display, MetaWindow *window)
g_signal_emit_by_name (window->display, "window-marked-urgent", window);
}
#ifdef HAVE_WAYLAND
MetaWindow *
meta_window_new_for_wayland (MetaDisplay *display,
int width,
@@ -1447,7 +1442,6 @@ meta_window_new_for_wayland (MetaDisplay *display,
return window;
}
#endif
MetaWindow*
meta_window_new_with_attrs (MetaDisplay *display,
@@ -2107,10 +2101,8 @@ meta_window_unmanage (MetaWindow *window,
meta_error_trap_pop (window->display);
}
#ifdef HAVE_WAYLAND
if (window->surface)
meta_wayland_surface_free (window->surface);
#endif
meta_prefs_remove_listener (prefs_changed_callback, window);
@@ -6012,7 +6004,7 @@ meta_window_get_outer_rect (const MetaWindow *window,
if (window->has_custom_frame_extents)
{
GtkBorder *extents = &window->custom_frame_extents;
const GtkBorder *extents = &window->custom_frame_extents;
rect->x += extents->left;
rect->y += extents->top;
rect->width -= extents->left + extents->right;
@@ -7399,9 +7391,6 @@ void
meta_window_set_focused_internal (MetaWindow *window,
gboolean focused)
{
if (window->unmanaging)
return;
if (focused)
{
window->has_focus = TRUE;
@@ -8579,10 +8568,13 @@ recalc_window_features (MetaWindow *window)
case META_WINDOW_DIALOG:
case META_WINDOW_MODAL_DIALOG:
/* only skip taskbar if we have a real transient parent */
/* only skip taskbar if we have a real transient parent
(and ignore the application hints) */
if (window->xtransient_for != None &&
window->xtransient_for != window->screen->xroot)
window->skip_taskbar = TRUE;
else
window->skip_taskbar = FALSE;
break;
case META_WINDOW_NORMAL:

35
src/idle-monitor.xml Normal file
View File

@@ -0,0 +1,35 @@
<!DOCTYPE node PUBLIC
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Mutter.IdleMonitor:
@short_description: idle monitor interface
This interface is used by gnome-desktop to implement
user activity monitoring.
-->
<interface name="org.gnome.Mutter.IdleMonitor">
<method name="GetIdletime">
<arg name="idletime" direction="out" type="t"/>
</method>
<method name="AddIdleWatch">
<arg name="interval" direction="in" type="t" />
<arg name="id" direction="out" type="u" />
</method>
<method name="AddUserActiveWatch">
<arg name="id" direction="out" type="u" />
</method>
<method name="RemoveWatch">
<arg name="id" direction="in" type="u" />
</method>
<signal name="WatchFired">
<arg name="id" direction="out" type="u" />
</signal>
</interface>
</node>

View File

@@ -0,0 +1,18 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
girdir=@libdir@/mutter-wayland
typelibdir=@libdir@/mutter-wayland
mutter_major_version=@MUTTER_MAJOR_VERSION@
mutter_minor_version=@MUTTER_MINOR_VERSION@
mutter_micro_version=@MUTTER_MICRO_VERSION@
mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@
Name: libmutter-wayland
Description: Mutter window manager library (Wayland branch)
Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11 wayland-server
Version: @VERSION@
Libs: -L${libdir} -lmutter-wayland
Cflags: -I${includedir}/mutter-wayland -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version}

View File

@@ -1,18 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
girdir=@libdir@/mutter
typelibdir=@libdir@/mutter
mutter_major_version=@MUTTER_MAJOR_VERSION@
mutter_minor_version=@MUTTER_MINOR_VERSION@
mutter_micro_version=@MUTTER_MICRO_VERSION@
mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@
Name: libmutter
Description: Mutter window manager library
Requires: gsettings-desktop-schemas gtk+-3.0 @CLUTTER_PACKAGE@ x11
Version: @VERSION@
Libs: -L${libdir} -lmutter
Cflags: -I${includedir}/mutter -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version}

View File

@@ -27,6 +27,7 @@
#include <glib-object.h>
#include <meta/types.h>
#include <meta/workspace.h>
#include <cogl/cogl.h>
#define META_TYPE_CURSOR_TRACKER (meta_cursor_tracker_get_type ())
#define META_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTracker))

View File

@@ -57,6 +57,6 @@ guint meta_idle_monitor_add_user_active_watch (MetaIdleMonitor
void meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
guint id);
guint64 meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor);
gint64 meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor);
#endif

View File

@@ -29,11 +29,6 @@
#include <clutter/clutter.h>
#include <X11/Xlib.h>
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
#include "meta-wayland-private.h"
#endif
G_BEGIN_DECLS
#define META_TYPE_SHAPED_TEXTURE (meta_shaped_texture_get_type())
@@ -69,14 +64,6 @@ struct _MetaShapedTexture
GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
ClutterActor *meta_shaped_texture_new_with_xwindow (Window xwindow);
#ifdef HAVE_WAYLAND
ClutterActor *meta_shaped_texture_new_with_wayland_surface (MetaWaylandSurface *surface);
void meta_shaped_texture_set_wayland_surface (MetaShapedTexture *stex,
MetaWaylandSurface *surface);
MetaWaylandSurface *meta_shaped_texture_get_wayland_surface (MetaShapedTexture *stex);
#endif
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps);
@@ -86,13 +73,6 @@ void meta_shaped_texture_update_area (MetaShapedTexture *stex,
int width,
int height);
void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
Pixmap pixmap);
#ifdef HAVE_WAYLAND
void meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
MetaWaylandBuffer *buffer);
#endif
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,

View File

@@ -1,17 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
plugindir=@MUTTER_PLUGIN_DIR@
libgnome_serverdir=@libexecdir@
mutter_major_version=@MUTTER_MAJOR_VERSION@
mutter_minor_version=@MUTTER_MINOR_VERSION@
mutter_micro_version=@MUTTER_MICRO_VERSION@
mutter_plugin_api_version=@MUTTER_PLUGIN_API_VERSION@
Name: mutter-plugins
Description: Dev parameters for mutter plugins
Requires: @CLUTTER_PACKAGE@
Version: @VERSION@
Libs: @CLUTTER_LIBS@
Cflags: @CLUTTER_CFLAGS@ -DWITH_CLUTTER -I${includedir}/mutter/mutter-private -DMUTTER_MAJOR_VERSION=${mutter_major_version} -DMUTTER_MINOR_VERSION=${mutter_minor_version} -DMUTTER_MICRO_VERSION=${mutter_micro_version} -DMUTTER_PLUGIN_API_VERSION=${mutter_plugin_api_version} -DMUTTER_PLUGIN_DIR=\"${plugindir}\"

View File

@@ -1,7 +1,7 @@
[Desktop Entry]
Type=Application
_Name=Mutter
Exec=mutter
_Name=Mutter (wayland compositor)
Exec=mutter-launch -- mutter --nested
NoDisplay=true
# name of loadable control center module
X-GNOME-WMSettingsModule=metacity
@@ -12,6 +12,5 @@ X-GnomeWMSettingsLibrary=metacity
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=mutter
X-GNOME-Bugzilla-Component=general
X-GNOME-Autostart-Phase=WindowManager
X-GNOME-Provides=windowmanager
X-GNOME-Autostart-Phase=DisplayServer
X-GNOME-Autostart-Notify=true

View File

@@ -1,20 +0,0 @@
[Desktop Entry]
Type=Application
_Name=Mutter
Exec=mutter
# name of loadable control center module
X-GNOME-WMSettingsModule=metacity
# name we put on the WM spec check window
X-GNOME-WMName=Mutter
# back compat only
X-GnomeWMSettingsLibrary=metacity
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=mutter
X-GNOME-Bugzilla-Component=general
X-GNOME-Autostart-Phase=WindowManager
X-GNOME-Provides=windowmanager
X-GNOME-Autostart-Notify=true
[Window Manager]
SessionManaged=true

View File

@@ -116,34 +116,5 @@
<_summary>Cancel tab popup</_summary>
</key>
<key name="switch-to-session-1" type="as">
<default><![CDATA[['<Primary><Alt>F1']]]></default>
<_summary>Switch to VT 1</_summary>
</key>
<key name="switch-to-session-2" type="as">
<default><![CDATA[['<Primary><Alt>F2']]]></default>
<_summary>Switch to VT 2</_summary>
</key>
<key name="switch-to-session-3" type="as">
<default><![CDATA[['<Primary><Alt>F3']]]></default>
<_summary>Switch to VT 3</_summary>
</key>
<key name="switch-to-session-4" type="as">
<default><![CDATA[['<Primary><Alt>F4']]]></default>
<_summary>Switch to VT 4</_summary>
</key>
<key name="switch-to-session-5" type="as">
<default><![CDATA[['<Primary><Alt>F5']]]></default>
<_summary>Switch to VT 5</_summary>
</key>
<key name="switch-to-session-6" type="as">
<default><![CDATA[['<Primary><Alt>F6']]]></default>
<_summary>Switch to VT 6</_summary>
</key>
<key name="switch-to-session-7" type="as">
<default><![CDATA[['<Primary><Alt>F7']]]></default>
<_summary>Switch to VT 7</_summary>
</key>
</schema>
</schemalist>

View File

@@ -0,0 +1,33 @@
<schemalist>
<schema id="org.gnome.mutter.wayland.keybindings" path="/org/gnome/mutter/wayland/keybindings/"
gettext-domain="@GETTEXT_DOMAIN@">
<key name="switch-to-session-1" type="as">
<default><![CDATA[['<Primary><Alt>F1']]]></default>
<_summary>Switch to VT 1</_summary>
</key>
<key name="switch-to-session-2" type="as">
<default><![CDATA[['<Primary><Alt>F2']]]></default>
<_summary>Switch to VT 2</_summary>
</key>
<key name="switch-to-session-3" type="as">
<default><![CDATA[['<Primary><Alt>F3']]]></default>
<_summary>Switch to VT 3</_summary>
</key>
<key name="switch-to-session-4" type="as">
<default><![CDATA[['<Primary><Alt>F4']]]></default>
<_summary>Switch to VT 4</_summary>
</key>
<key name="switch-to-session-5" type="as">
<default><![CDATA[['<Primary><Alt>F5']]]></default>
<_summary>Switch to VT 5</_summary>
</key>
<key name="switch-to-session-6" type="as">
<default><![CDATA[['<Primary><Alt>F6']]]></default>
<_summary>Switch to VT 6</_summary>
</key>
<key name="switch-to-session-7" type="as">
<default><![CDATA[['<Primary><Alt>F7']]]></default>
<_summary>Switch to VT 7</_summary>
</key>
</schema>
</schemalist>

View File

@@ -56,6 +56,8 @@ struct _MetaUI
void
meta_ui_init (void)
{
gdk_set_allowed_backends ("x11");
if (!gtk_init_check (NULL, NULL))
meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
}

View File

@@ -1,436 +0,0 @@
/*
* Copyright © 2010 Intel Corporation
* 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.
*/
#include "config.h"
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include <linux/major.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "meta-tty.h"
#include <gio/gio.h>
#include <glib-unix.h>
/* Introduced in 2.6.38 */
#ifndef K_OFF
#define K_OFF 0x04
#endif
struct _MetaTTYClass
{
GObjectClass parent_class;
};
struct _MetaTTY
{
GObject parent;
int fd;
struct termios terminal_attributes;
GMainContext *nested_context;
GMainLoop *nested_loop;
int input_source;
GSource *vt_enter_source, *vt_leave_source;
GSource *nested_term;
int vt, starting_vt;
int kb_mode;
};
enum {
SIGNAL_ENTER,
SIGNAL_LEAVE,
SIGNAL_LAST
};
static int signals[SIGNAL_LAST];
static void meta_tty_initable_iface_init (GInitableIface *);
G_DEFINE_TYPE_WITH_CODE (MetaTTY, meta_tty, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
meta_tty_initable_iface_init));
static gboolean
quit_nested_loop (gpointer user_data)
{
MetaTTY *tty = user_data;
g_main_loop_quit (tty->nested_loop);
return FALSE;
}
static gboolean
vt_release_handler (gpointer user_data)
{
MetaTTY *tty = user_data;
g_signal_emit (tty, signals[SIGNAL_LEAVE], 0);
ioctl (tty->fd, VT_RELDISP, 1);
/* 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 (tty->nested_loop);
ioctl (tty->fd, VT_RELDISP, VT_ACKACQ);
g_signal_emit (tty, signals[SIGNAL_ENTER], 0);
return FALSE;
}
static int
on_tty_input (int fd,
GIOCondition mask,
gpointer user_data)
{
MetaTTY *tty = user_data;
/* Ignore input to tty. We get keyboard events from evdev */
tcflush(tty->fd, TCIFLUSH);
return 1;
}
static int
try_open_vt (MetaTTY *tty,
GError **error)
{
int tty0, fd;
char filename[16];
tty0 = open ("/dev/tty0", O_WRONLY | O_CLOEXEC);
if (tty0 < 0)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Could not open tty0: %s", strerror (errno));
return -1;
}
if (ioctl (tty0, VT_OPENQRY, &tty->vt) < 0 || tty->vt == -1) {
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Could not open tty0: %s", strerror (errno));
close (tty0);
return -1;
}
close (tty0);
snprintf (filename, sizeof filename, "/dev/tty%d", tty->vt);
g_debug("compositor: using new vt %s\n", filename);
fd = open (filename, O_RDWR | O_NOCTTY | O_CLOEXEC);
return fd;
}
gboolean
meta_tty_activate_vt (MetaTTY *tty,
int vt,
GError **error)
{
if (ioctl(tty->fd, VT_ACTIVATE, vt) < 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
strerror (errno));
return FALSE;
}
else
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);
}
static gboolean
meta_tty_initable_init(GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaTTY *tty = META_TTY (initable);
struct termios raw_attributes;
struct vt_mode mode = { 0 };
int ret;
struct stat buf;
struct vt_stat vts;
tty->fd = env_get_fd ("WESTON_TTY_FD");
if (tty->fd < 0)
tty->fd = STDIN_FILENO;
if (fstat(tty->fd, &buf) == 0 &&
major(buf.st_rdev) == TTY_MAJOR &&
minor(buf.st_rdev) > 0)
{
if (tty->fd == STDIN_FILENO)
tty->fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0);
tty->vt = minor(buf.st_rdev);
}
else
{
/* Fall back to try opening a new VT. This typically
* requires root. */
tty->fd = try_open_vt(tty, error);
}
if (tty->fd <= 0 && (!error || !*error))
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Could not open tty0: %s", strerror (errno));
return FALSE;
}
if (ioctl(tty->fd, VT_GETSTATE, &vts) == 0)
tty->starting_vt = vts.v_active;
else
tty->starting_vt = tty->vt;
if (tty->starting_vt != tty->vt)
{
if (ioctl(tty->fd, VT_ACTIVATE, tty->vt) < 0 ||
ioctl(tty->fd, VT_WAITACTIVE, tty->vt) < 0)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Failed to switch to new vt: %s", strerror (errno));
goto err;
}
}
if (tcgetattr(tty->fd, &tty->terminal_attributes) < 0)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Could not get terminal attributes: %s", strerror (errno));
goto err;
}
/* Ignore control characters and disable echo */
raw_attributes = tty->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(tty->fd, TCSANOW, &raw_attributes) < 0)
g_warning("Could not put terminal into raw mode: %s", strerror (errno));
ioctl(tty->fd, KDGKBMODE, &tty->kb_mode);
ret = ioctl(tty->fd, KDSKBMODE, K_OFF);
if (ret)
{
ret = ioctl(tty->fd, KDSKBMODE, K_RAW);
if (ret)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Failed to set keyboard mode: %s", strerror (errno));
goto err_attr;
}
tty->input_source = g_unix_fd_add (tty->fd,
G_IO_IN,
on_tty_input, tty);
}
ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS);
if (ret)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Failed to set KD_GRAPHICS mode: %s", strerror (errno));
goto err_kdkbmode;
}
mode.mode = VT_PROCESS;
mode.relsig = SIGUSR1;
mode.acqsig = SIGUSR2;
if (ioctl(tty->fd, VT_SETMODE, &mode) < 0)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
"Failed to take control of vt handling: %s", strerror (errno));
goto err_kdmode;
}
tty->vt_leave_source = g_unix_signal_source_new (SIGUSR1);
g_source_set_callback (tty->vt_leave_source, vt_release_handler, tty, NULL);
tty->vt_enter_source = g_unix_signal_source_new (SIGUSR2);
g_source_set_callback (tty->vt_enter_source, quit_nested_loop, tty, NULL);
tty->nested_term = g_unix_signal_source_new (SIGTERM);
g_source_set_callback (tty->nested_term, quit_nested_loop, tty, NULL);
tty->nested_context = g_main_context_new ();
tty->nested_loop = g_main_loop_new (tty->nested_context, FALSE);
g_source_attach (tty->vt_leave_source, NULL);
g_source_attach (tty->vt_enter_source, tty->nested_context);
g_source_attach (tty->nested_term, tty->nested_context);
return TRUE;
err_kdmode:
ioctl (tty->fd, KDSETMODE, KD_TEXT);
err_kdkbmode:
if (tty->input_source)
g_source_remove (tty->input_source);
ioctl (tty->fd, KDSKBMODE, tty->kb_mode);
err_attr:
tcsetattr (tty->fd, TCSANOW, &tty->terminal_attributes);
err:
close (tty->fd);
return FALSE;
}
void
meta_tty_reset (MetaTTY *tty,
gboolean warn_if_fail)
{
struct vt_mode mode = { 0 };
if (ioctl (tty->fd, KDSKBMODE, tty->kb_mode) && warn_if_fail)
g_warning ("failed to restore keyboard mode: %s", strerror (errno));
if (ioctl (tty->fd, KDSETMODE, KD_TEXT) && warn_if_fail)
g_warning ("failed to set KD_TEXT mode on tty: %s", strerror (errno));
if (tcsetattr (tty->fd, TCSANOW, &tty->terminal_attributes) < 0 && warn_if_fail)
g_warning ("could not restore terminal to canonical mode");
mode.mode = VT_AUTO;
if (ioctl (tty->fd, VT_SETMODE, &mode) < 0 && warn_if_fail)
g_warning ("could not reset vt handling\n");
if (tty->vt != tty->starting_vt)
{
ioctl(tty->fd, VT_ACTIVATE, tty->starting_vt);
ioctl(tty->fd, VT_WAITACTIVE, tty->starting_vt);
}
}
static void
meta_tty_finalize (GObject *object)
{
MetaTTY *tty = META_TTY (object);
if (tty->input_source)
g_source_remove (tty->input_source);
g_source_destroy (tty->vt_enter_source);
g_source_destroy (tty->vt_leave_source);
g_source_destroy (tty->nested_term);
g_main_loop_unref (tty->nested_loop);
g_main_context_unref (tty->nested_context);
meta_tty_reset (tty, TRUE);
close (tty->fd);
G_OBJECT_CLASS (meta_tty_parent_class)->finalize (object);
}
static void
meta_tty_init (MetaTTY *self)
{
}
static void
meta_tty_class_init (MetaTTYClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_tty_finalize;
signals[SIGNAL_ENTER] = g_signal_new ("enter",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, /* class offset */
NULL, NULL, /* accumulator */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[SIGNAL_LEAVE] = g_signal_new ("leave",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, /* class offset */
NULL, NULL, /* accumulator */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
meta_tty_initable_iface_init (GInitableIface *iface)
{
iface->init = meta_tty_initable_init;
}
MetaTTY *
meta_tty_new (void)
{
GError *error;
MetaTTY *tty;
error = NULL;
tty = g_initable_new (META_TYPE_TTY, NULL, &error, NULL);
if (tty == NULL)
{
g_warning ("Failed to initalize TTY handling: %s", error->message);
g_error_free (error);
}
return tty;
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright (C) 2013 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_TTY_H
#define META_TTY_H
#include <glib-object.h>
G_BEGIN_DECLS
#define META_TYPE_TTY (meta_tty_get_type())
#define META_TTY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_TTY, MetaTTY))
#define META_TTY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_TTY, MetaTTYClass))
#define META_IS_TTY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_TTY))
#define META_IS_TTY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_TTY))
#define META_TTY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TTY, MetaTTYClass))
typedef struct _MetaTTY MetaTTY;
typedef struct _MetaTTYClass MetaTTYClass;
GType meta_tty_get_type (void) G_GNUC_CONST;
MetaTTY *meta_tty_new (void);
gboolean meta_tty_activate_vt (MetaTTY *self,
int number,
GError **error);
void meta_tty_reset (MetaTTY *self,
gboolean warn_if_fail);
G_END_DECLS
#endif /* META_TTY_H */

View File

@@ -56,7 +56,6 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <clutter/evdev/clutter-evdev.h>
#include "meta-wayland-keyboard.h"
@@ -259,11 +258,12 @@ default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
pointer->focus);
if (pr)
{
wl_keyboard_send_modifiers (pr, serial,
mods_depressed,
mods_latched,
mods_locked,
group);
wl_keyboard_send_modifiers (pr,
serial,
keyboard->modifiers.mods_depressed,
keyboard->modifiers.mods_latched,
keyboard->modifiers.mods_locked,
keyboard->modifiers.group);
}
}
}
@@ -276,11 +276,8 @@ static const MetaWaylandKeyboardGrabInterface
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display,
gboolean is_evdev)
struct wl_display *display)
{
ClutterDeviceManager *manager;
memset (keyboard, 0, sizeof *keyboard);
wl_list_init (&keyboard->resource_list);
@@ -296,22 +293,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->xkb_context = xkb_context_new (0 /* flags */);
meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
&keyboard->xkb_names,
&keyboard->xkb_info);
keyboard->is_evdev = is_evdev;
if (is_evdev)
{
manager = clutter_device_manager_get_default ();
clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap);
keyboard->xkb_state = clutter_evdev_get_keyboard_state (manager);
xkb_state_ref (keyboard->xkb_state);
}
else
{
keyboard->xkb_state = xkb_state_new (keyboard->xkb_info.keymap);
}
&keyboard->xkb_names,
&keyboard->xkb_info);
return TRUE;
}
@@ -329,12 +312,17 @@ meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
}
static void
update_state_from_clutter (MetaWaylandKeyboard *keyboard,
ClutterModifierType modifier_state)
set_modifiers (MetaWaylandKeyboard *keyboard,
guint32 serial,
ClutterModifierType modifier_state)
{
MetaWaylandKeyboardGrab *grab = keyboard->grab;
uint32_t depressed_mods = 0;
uint32_t locked_mods = 0;
if (keyboard->last_modifier_state == modifier_state)
return;
if ((modifier_state & CLUTTER_SHIFT_MASK) &&
keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
@@ -367,56 +355,14 @@ update_state_from_clutter (MetaWaylandKeyboard *keyboard,
keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
xkb_state_update_mask (keyboard->xkb_state,
depressed_mods,
0,
locked_mods,
0, 0, 0);
}
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,
ClutterModifierType modifier_state)
{
MetaWaylandKeyboardGrab *grab = keyboard->grab;
MetaWaylandXkbState new_state;
/* In the evdev case, the state is shared with the clutter backend, so
we don't need to update it */
if (!keyboard->is_evdev)
update_state_from_clutter (keyboard, modifier_state);
new_state.mods_depressed = xkb_state_serialize_mods (keyboard->xkb_state,
XKB_STATE_MODS_DEPRESSED);
new_state.mods_latched = xkb_state_serialize_mods (keyboard->xkb_state,
XKB_STATE_MODS_LATCHED);
new_state.mods_locked = xkb_state_serialize_mods (keyboard->xkb_state,
XKB_STATE_MODS_LOCKED);
new_state.group = xkb_state_serialize_layout (keyboard->xkb_state,
XKB_STATE_LAYOUT_EFFECTIVE);
if (state_equal (&keyboard->modifier_state, &new_state))
return;
keyboard->modifier_state = new_state;
keyboard->last_modifier_state = modifier_state;
grab->interface->modifiers (grab,
serial,
new_state.mods_depressed,
new_state.mods_latched,
new_state.mods_locked,
new_state.group);
depressed_mods,
0, /* latched_modes */
locked_mods,
0 /* group */);
}
void
@@ -470,7 +416,7 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
goto found;
}
g_warning ("unexpected key release event for key 0x%x (%d)", evdev_code, event->keyval);
g_warning ("unexpected key release event for key 0x%x", evdev_code);
found:
(void) 0;
@@ -516,10 +462,10 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
display = wl_client_get_display (client);
serial = wl_display_next_serial (display);
wl_keyboard_send_modifiers (resource, serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
keyboard->modifiers.mods_depressed,
keyboard->modifiers.mods_latched,
keyboard->modifiers.mods_locked,
keyboard->modifiers.group);
wl_keyboard_send_enter (resource, serial, surface->resource,
&keyboard->keys);
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
@@ -558,61 +504,9 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
xkb_context_unref (keyboard->xkb_context);
xkb_state_unref (keyboard->xkb_state);
/* XXX: What about keyboard->resource_list? */
if (keyboard->focus_resource)
wl_list_remove (&keyboard->focus_listener.link);
wl_array_release (&keyboard->keys);
}
static void
modal_key (MetaWaylandKeyboardGrab *grab,
uint32_t time,
uint32_t key,
uint32_t state)
{
}
static void
modal_modifiers (MetaWaylandKeyboardGrab *grab,
uint32_t serial,
uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked,
uint32_t group)
{
}
static MetaWaylandKeyboardGrabInterface modal_grab = {
modal_key,
modal_modifiers,
};
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard)
{
MetaWaylandKeyboardGrab *grab;
if (keyboard->grab != &keyboard->default_grab)
return FALSE;
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
grab->interface = &modal_grab;
meta_wayland_keyboard_start_grab (keyboard, grab);
return TRUE;
}
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard)
{
MetaWaylandKeyboardGrab *grab;
grab = keyboard->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_keyboard_end_grab (keyboard);
g_slice_free (MetaWaylandKeyboardGrab, grab);
}

View File

@@ -52,8 +52,7 @@
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display,
gboolean is_evdev);
struct wl_display *display);
void
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
@@ -70,11 +69,6 @@ meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
void
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard);
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard);
void
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);

View File

@@ -194,10 +194,10 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
{
wl_keyboard_send_modifiers (kr,
serial,
kbd->modifier_state.mods_depressed,
kbd->modifier_state.mods_latched,
kbd->modifier_state.mods_locked,
kbd->modifier_state.group);
kbd->modifiers.mods_depressed,
kbd->modifiers.mods_latched,
kbd->modifiers.mods_locked,
kbd->modifiers.group);
}
}
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
@@ -262,65 +262,3 @@ meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
&pointer->current_listener);
pointer->current_listener.notify = current_surface_destroy;
}
static void
modal_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
{
}
static void
modal_motion (MetaWaylandPointerGrab *grab,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
{
}
static void
modal_button (MetaWaylandPointerGrab *grab,
uint32_t time,
uint32_t button,
uint32_t state)
{
}
static MetaWaylandPointerGrabInterface modal_grab = {
modal_focus,
modal_motion,
modal_button
};
gboolean
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
if (pointer->grab != &pointer->default_grab)
return FALSE;
meta_wayland_pointer_set_focus (pointer, NULL,
wl_fixed_from_int (0),
wl_fixed_from_int (0));
grab = g_slice_new0 (MetaWaylandPointerGrab);
grab->interface = &modal_grab;
meta_wayland_pointer_start_grab (pointer, grab);
return TRUE;
}
void
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
grab = pointer->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_pointer_end_grab (pointer);
g_slice_free (MetaWaylandPointerGrab, grab);
}

View File

@@ -42,11 +42,6 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
gboolean
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);

View File

@@ -28,7 +28,7 @@
#include <cairo.h>
#include "window-private.h"
#include "meta-tty.h"
#include "meta-weston-launch.h"
#include <meta/meta-cursor-tracker.h>
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
@@ -52,7 +52,9 @@ typedef struct
union
{
struct wl_shm_buffer *shm_buffer;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
struct wl_buffer *legacy_buffer;
G_GNUC_END_IGNORE_DEPRECATIONS;
};
int32_t width, height;
@@ -130,12 +132,11 @@ typedef struct
struct _MetaWaylandCompositor
{
GHashTable *outputs;
struct wl_display *wayland_display;
struct wl_event_loop *wayland_loop;
GMainLoop *init_loop;
ClutterActor *stage;
GHashTable *outputs;
GSource *wayland_event_source;
GList *surfaces;
struct wl_list frame_callbacks;
@@ -148,9 +149,8 @@ struct _MetaWaylandCompositor
struct wl_client *xwayland_client;
struct wl_resource *xserver_resource;
MetaTTY *tty;
MetaLauncher *launcher;
int drm_fd;
GSocket *weston_launch;
MetaWaylandSeat *seat;
@@ -238,14 +238,6 @@ typedef struct
xkb_mod_index_t mod5_mod;
} 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;
@@ -263,19 +255,25 @@ struct _MetaWaylandKeyboard
struct wl_array keys;
MetaWaylandXkbState modifier_state;
struct
{
uint32_t mods_depressed;
uint32_t mods_latched;
uint32_t mods_locked;
uint32_t group;
} modifiers;
struct wl_display *display;
struct xkb_context *xkb_context;
struct xkb_state *xkb_state;
gboolean is_evdev;
MetaWaylandXkbInfo xkb_info;
struct xkb_rule_names xkb_names;
MetaWaylandKeyboardGrab input_method_grab;
struct wl_resource *input_method_resource;
ClutterModifierType last_modifier_state;
};
struct _MetaWaylandDataOffer
@@ -344,8 +342,7 @@ void meta_wayland_compositor_repick (MetaWaylandComp
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window);
MetaTTY *meta_wayland_compositor_get_tty (MetaWaylandCompositor *compositor);
gboolean meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor);
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
void meta_wayland_surface_free (MetaWaylandSurface *surface);

View File

@@ -35,6 +35,7 @@
#include "meta-wayland-data-device.h"
#include "meta-window-actor-private.h"
#include "meta/meta-shaped-texture.h"
#include "meta-shaped-texture-private.h"
#include "meta-wayland-stage.h"
#include "meta-cursor-tracker-private.h"
@@ -270,8 +271,7 @@ pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
}
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native)
meta_wayland_seat_new (struct wl_display *display)
{
MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
@@ -285,7 +285,7 @@ meta_wayland_seat_new (struct wl_display *display,
meta_wayland_pointer_init (&seat->pointer);
meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
meta_wayland_keyboard_init (&seat->keyboard, display);
seat->display = display;

View File

@@ -30,8 +30,7 @@
#include "meta-wayland-private.h"
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native);
meta_wayland_seat_new (struct wl_display *display);
void
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,

View File

@@ -65,4 +65,3 @@ meta_wayland_stage_new (void)
"cursor-visible", FALSE,
NULL);
}

View File

@@ -24,7 +24,6 @@
#include <clutter/clutter.h>
#include <clutter/wayland/clutter-wayland-compositor.h>
#include <clutter/wayland/clutter-wayland-surface.h>
#include <clutter/evdev/clutter-evdev.h>
#include <glib.h>
#include <sys/time.h>
@@ -32,8 +31,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <wayland-server.h>
@@ -52,8 +49,9 @@
#include <meta/types.h>
#include <meta/main.h>
#include "frame.h"
#include "meta-weston-launch.h"
#include "meta-idle-monitor-private.h"
#include "meta-weston-launch.h"
#include "monitor-private.h"
static MetaWaylandCompositor _meta_wayland_compositor;
@@ -214,20 +212,6 @@ surface_process_damage (MetaWaylandSurface *surface,
MetaWindowActor *window_actor =
META_WINDOW_ACTOR (meta_window_get_compositor_private (surface->window));
if (!surface->window->override_redirect)
{
MetaRectangle rect;
cairo_rectangle_int_t cairo_rect;
meta_window_get_input_rect (surface->window, &rect);
cairo_rect.x = 0;
cairo_rect.y = 0;
cairo_rect.width = rect.width;
cairo_rect.height = rect.height;
cairo_region_intersect_rectangle (region, &cairo_rect);
}
if (window_actor)
{
int i, n_rectangles = cairo_region_num_rectangles (region);
@@ -683,38 +667,40 @@ bind_output (struct wl_client *client,
wl_resource_set_destructor (resource, output_resource_destroy);
meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n",
output, output->name,
output->crtc->rect.x, output->crtc->rect.y,
output->crtc->rect.width, output->crtc->rect.height,
output->crtc->current_mode->refresh_rate);
output, output->name,
output->crtc->rect.x, output->crtc->rect.y,
output->crtc->rect.width, output->crtc->rect.height,
output->crtc->current_mode->refresh_rate);
wl_resource_post_event (resource,
WL_OUTPUT_GEOMETRY,
(int)output->crtc->rect.x,
(int)output->crtc->rect.y,
output->width_mm,
(int)output->crtc->rect.y,
output->width_mm,
output->height_mm,
/* Cogl values reflect XRandR values,
and so does wayland */
output->subpixel_order,
output->vendor,
output->product,
output->crtc->transform);
/* Cogl values reflect XRandR values,
and so does wayland */
output->subpixel_order,
output->vendor,
output->product,
output->crtc->transform);
g_assert (output->crtc->current_mode != NULL);
mode_flags = WL_OUTPUT_MODE_CURRENT;
if (output->crtc->current_mode == output->preferred_mode)
mode_flags |= WL_OUTPUT_MODE_PREFERRED;
wl_resource_post_event (resource,
WL_OUTPUT_MODE,
mode_flags,
(int)output->crtc->rect.width,
(int)output->crtc->rect.height,
(int)output->crtc->current_mode->refresh_rate);
WL_OUTPUT_MODE,
mode_flags,
(int)output->crtc->current_mode->width,
(int)output->crtc->current_mode->height,
(int)output->crtc->current_mode->refresh_rate);
if (version >= 2)
wl_resource_post_event (resource,
WL_OUTPUT_DONE);
WL_OUTPUT_DONE);
}
static void
@@ -735,11 +721,13 @@ wayland_output_destroy_notify (gpointer data)
static void
wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
MetaOutput *output)
MetaOutput *output)
{
GList *iter;
guint mode_flags;
g_assert (output->crtc->current_mode != NULL);
mode_flags = WL_OUTPUT_MODE_CURRENT;
if (output->crtc->current_mode == output->preferred_mode)
mode_flags |= WL_OUTPUT_MODE_PREFERRED;
@@ -749,27 +737,27 @@ wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
struct wl_resource *resource = iter->data;
if (wayland_output->x != output->crtc->rect.x ||
wayland_output->y != output->crtc->rect.y ||
wayland_output->transform != output->crtc->transform)
{
wl_resource_post_event (resource,
WL_OUTPUT_GEOMETRY,
(int)output->crtc->rect.x,
(int)output->crtc->rect.y,
output->width_mm,
output->height_mm,
output->subpixel_order,
output->vendor,
output->product,
output->crtc->transform);
}
wayland_output->y != output->crtc->rect.y ||
wayland_output->transform != output->crtc->transform)
{
wl_resource_post_event (resource,
WL_OUTPUT_GEOMETRY,
(int)output->crtc->rect.x,
(int)output->crtc->rect.y,
output->width_mm,
output->height_mm,
output->subpixel_order,
output->vendor,
output->product,
output->crtc->transform);
}
wl_resource_post_event (resource,
WL_OUTPUT_MODE,
mode_flags,
(int)output->crtc->rect.width,
(int)output->crtc->rect.height,
(int)output->crtc->current_mode->refresh_rate);
WL_OUTPUT_MODE,
mode_flags,
(int)output->crtc->current_mode->width,
(int)output->crtc->current_mode->height,
(int)output->crtc->current_mode->refresh_rate);
}
/* It's very important that we change the output pointer here, as
@@ -782,7 +770,7 @@ wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
static GHashTable *
meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
MetaMonitorManager *monitors)
MetaMonitorManager *monitors)
{
MetaOutput *outputs;
unsigned int i, n_outputs;
@@ -798,24 +786,24 @@ meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
/* wayland does not expose disabled outputs */
if (output->crtc == NULL)
{
g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
continue;
}
{
g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
continue;
}
wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
if (wayland_output)
{
g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
}
{
g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
}
else
{
wayland_output = g_slice_new0 (MetaWaylandOutput);
wayland_output->global = wl_global_create (compositor->wayland_display,
&wl_output_interface, 2,
wayland_output, bind_output);
}
{
wayland_output = g_slice_new0 (MetaWaylandOutput);
wayland_output->global = wl_global_create (compositor->wayland_display,
&wl_output_interface, 2,
wayland_output, bind_output);
}
wayland_output_update_for_output (wayland_output, output);
g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output);
@@ -1258,55 +1246,6 @@ bind_shell (struct wl_client *client,
wl_resource_set_implementation (resource, &meta_wayland_shell_interface, data, NULL);
}
static void
gnome_session_died (GPid pid,
gint status,
gpointer user_data)
{
if (!WIFEXITED (status))
g_error ("gnome-session crashed; aborting");
else
{
/* A clean exit of gnome-session implies a logout, exit cleanly */
meta_quit (META_EXIT_SUCCESS);
}
}
static void
start_gnome_session (MetaWaylandCompositor *compositor)
{
GPid pid;
char *args[6];
GError *error;
args[0] = "setsid";
args[1] = "gnome-session";
args[2] = "--session";
args[3] = "gnome-wayland";
args[4] = "--debug";
args[5] = NULL;
error = NULL;
if (g_spawn_async (NULL, /* cwd */
args,
NULL,
G_SPAWN_SEARCH_PATH |
G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
&pid,
&error))
{
g_message ("forked gnome-session, pid %d\n", pid);
g_child_watch_add (pid, gnome_session_died, NULL);
}
else
{
g_error ("Failed to fork gnome-session server: %s", error->message);
}
}
static void
stage_destroy_cb (void)
{
@@ -1429,11 +1368,11 @@ synthesize_motion_event (MetaWaylandCompositor *compositor,
static void
reset_idletimes (const ClutterEvent *event)
{
ClutterInputDevice *device;
ClutterInputDevice *device, *source_device;
MetaIdleMonitor *core_monitor, *device_monitor;
int device_id;
device = clutter_event_get_source_device (event);
device = clutter_event_get_device (event);
device_id = clutter_input_device_get_device_id (device);
core_monitor = meta_idle_monitor_get_core ();
@@ -1441,6 +1380,14 @@ reset_idletimes (const ClutterEvent *event)
meta_idle_monitor_reset_idletime (core_monitor);
meta_idle_monitor_reset_idletime (device_monitor);
source_device = clutter_event_get_source_device (event);
if (source_device != device)
{
device_id = clutter_input_device_get_device_id (device);
device_monitor = meta_idle_monitor_get_for_device (device_id);
meta_idle_monitor_reset_idletime (device_monitor);
}
}
static gboolean
@@ -1513,20 +1460,6 @@ event_cb (ClutterActor *stage,
synthesize_motion_event (compositor, event);
return FALSE;
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
meta_verbose ("Clutter key event %s for key %d (%d), state %d\n",
event->type == CLUTTER_KEY_PRESS ? "press" : "release",
clutter_event_get_key_symbol (event),
clutter_event_get_key_code (event),
clutter_event_get_state (event));
return FALSE;
case CLUTTER_SCROLL:
meta_verbose ("Clutter scroll event %s\n",
clutter_event_get_scroll_direction (event) == CLUTTER_SCROLL_DOWN ? "down" : "up");
return FALSE;
default:
return FALSE;
}
@@ -1584,101 +1517,22 @@ event_emission_hook_cb (GSignalInvocationHint *ihint,
return TRUE /* stay connected */;
}
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);
}
static void
on_our_vt_enter (MetaTTY *tty,
MetaWaylandCompositor *compositor)
{
GError *error;
error = NULL;
if (!meta_weston_launch_set_master (compositor->weston_launch,
compositor->drm_fd, TRUE, &error))
{
g_warning ("Failed to become DRM master: %s", error->message);
g_error_free (error);
}
clutter_evdev_reclaim_devices ();
}
static void
on_our_vt_leave (MetaTTY *tty,
MetaWaylandCompositor *compositor)
{
GError *error;
error = NULL;
if (!meta_weston_launch_set_master (compositor->weston_launch,
compositor->drm_fd, FALSE, &error))
{
g_warning ("Failed to release DRM master: %s", error->message);
g_error_free (error);
}
clutter_evdev_release_devices ();
}
static int
on_evdev_device_open (const char *path,
int flags,
gpointer user_data,
GError **error)
{
MetaWaylandCompositor *compositor = user_data;
return meta_weston_launch_open_input_device (compositor->weston_launch,
path, flags, error);
}
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaWaylandCompositor *compositor)
MetaWaylandCompositor *compositor)
{
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
}
static void
on_display_config_ready (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
gboolean ok;
ok = meta_monitor_manager_init_dbus_finish (META_MONITOR_MANAGER (object), result, NULL);
g_assert (ok);
meta_idle_monitor_init_dbus ();
/* Now we have X and DBus, and our stuff is on the bus.
The only thing missing is gnome-session! */
start_gnome_session (user_data);
}
void
meta_wayland_init (void)
{
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
guint event_signal;
MetaMonitorManager *monitors;
ClutterBackend *backend;
CoglContext *cogl_context;
CoglRenderer *cogl_renderer;
int weston_launch_fd;
MetaMonitorManager *monitors;
GDBusConnection *session_bus;
char *session_bus_address;
memset (compositor, 0, sizeof (MetaWaylandCompositor));
@@ -1715,12 +1569,8 @@ meta_wayland_init (void)
clutter_wayland_set_compositor_display (compositor->wayland_display);
/* We need to set this before clutter_init(), so we do it unconditionally.
It doesn't harm anyway to do it under X11 */
weston_launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
if (weston_launch_fd >= 0)
compositor->weston_launch = g_socket_new_from_fd (weston_launch_fd, NULL);
clutter_evdev_set_open_callback (on_evdev_device_open, compositor);
if (getenv ("WESTON_LAUNCHER_SOCK"))
compositor->launcher = meta_launcher_new ();
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
g_error ("Failed to initialize Clutter");
@@ -1737,54 +1587,26 @@ meta_wayland_init (void)
if (compositor->drm_fd >= 0)
{
GError *error;
char path[PATH_MAX];
int fd;
/* Running on bare metal, let's initalize DRM master and VT handling */
compositor->tty = meta_tty_new ();
if (compositor->tty)
{
g_signal_connect (compositor->tty, "enter", G_CALLBACK (on_our_vt_enter), compositor);
g_signal_connect (compositor->tty, "leave", G_CALLBACK (on_our_vt_leave), compositor);
}
meta_launcher_set_drm_fd (compositor->launcher, compositor->drm_fd);
error = NULL;
if (!meta_weston_launch_set_master (compositor->weston_launch,
compositor->drm_fd, TRUE, &error))
if (!meta_launcher_set_master (compositor->launcher, TRUE, &error))
{
g_error ("Failed to become DRM master: %s", error->message);
g_error_free (error);
}
/* Open a log in the home directory. This is necessary because otherwise
all background processes (such as gnome-session and children) get SIGTTOU
trying to write to the terminal.
Then close (</dev/null) stdin, so we don't get SIGTTIN or other crazy stuff.
*/
snprintf(path, PATH_MAX, "%s/gnome-wayland.log", g_get_user_cache_dir ());
fd = open (path, O_WRONLY | O_APPEND | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
fd = open ("/dev/null", O_WRONLY | O_NOCTTY, 0600);
dup2 (fd, STDOUT_FILENO);
dup2 (fd, STDERR_FILENO);
close (fd);
fd = open ("/dev/null", O_WRONLY | O_NOCTTY, 0600);
dup2 (fd, STDIN_FILENO);
}
meta_monitor_manager_initialize ();
monitors = meta_monitor_manager_get ();
g_signal_connect (monitors, "monitors-changed",
G_CALLBACK (on_monitors_changed), compositor);
G_CALLBACK (on_monitors_changed), compositor);
compositor->outputs = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
compositor->stage = meta_wayland_stage_new ();
g_signal_connect_after (compositor->stage, "paint",
G_CALLBACK (paint_finished_cb), compositor);
g_signal_connect (compositor->stage, "destroy",
@@ -1792,8 +1614,7 @@ meta_wayland_init (void)
meta_wayland_data_device_manager_init (compositor->wayland_display);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display,
compositor->drm_fd >= 0);
compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
g_signal_connect (compositor->stage,
"captured-event",
@@ -1815,6 +1636,8 @@ meta_wayland_init (void)
compositor, bind_shell) == NULL)
g_error ("Failed to register a global shell object");
clutter_actor_show (compositor->stage);
if (wl_display_add_socket (compositor->wayland_display, "wayland-0"))
g_error ("Failed to create socket");
@@ -1832,23 +1655,6 @@ meta_wayland_init (void)
g_error ("Failed to start X Wayland");
putenv (g_strdup_printf ("DISPLAY=:%d", compositor->xwayland_display_index));
/* Now xwayland is ready. Get ourselves a dbus daemon. This will autolaunch
if no bus is found.
*/
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
if (!session_bus)
meta_fatal ("Could not connect to the session bus\n");
session_bus_address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, NULL);
putenv (g_strdup_printf ("DBUS_SESSION_BUS_ADDRESS=%s", session_bus_address));
g_free (session_bus_address);
/* Now get our interface on the dbus (or gnome-settings-daemon will refuse
to start, which in turn will stall gnome-session from launching the rest
of the session)
*/
meta_monitor_manager_init_dbus (monitors, on_display_config_ready, compositor);
}
void
@@ -1859,17 +1665,11 @@ meta_wayland_finalize (void)
compositor = meta_wayland_compositor_get_default ();
meta_xwayland_stop (compositor);
g_clear_object (&compositor->tty);
g_clear_object (&compositor->launcher);
}
MetaTTY *
meta_wayland_compositor_get_tty (MetaWaylandCompositor *compositor)
MetaLauncher *
meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor)
{
return compositor->tty;
}
gboolean
meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor)
{
return compositor->drm_fd >= 0;
return compositor->launcher;
}

View File

@@ -22,6 +22,9 @@
#include <gio/gio.h>
#include <gio/gunixfdmessage.h>
#include <clutter/clutter.h>
#include <clutter/evdev/clutter-evdev.h>
#include <glib.h>
#include <sys/time.h>
#include <string.h>
@@ -40,6 +43,40 @@
#include "meta-weston-launch.h"
struct _MetaLauncherClass
{
GObjectClass parent_class;
void (*enter) (MetaLauncher *);
void (*leave) (MetaLauncher *);
};
struct _MetaLauncher
{
GObject parent;
GSocket *weston_launch;
int drm_fd;
gboolean vt_switched;
GMainContext *nested_context;
GMainLoop *nested_loop;
GSource *inner_source;
GSource *outer_source;
};
enum {
SIGNAL_ENTER,
SIGNAL_LEAVE,
SIGNAL_LAST
};
static int signals[SIGNAL_LAST];
G_DEFINE_TYPE (MetaLauncher, meta_launcher, G_TYPE_OBJECT);
static gboolean
send_message_to_wl (GSocket *weston_launch,
void *message,
@@ -98,106 +135,298 @@ send_message_to_wl (GSocket *weston_launch,
}
gboolean
meta_weston_launch_set_master (GSocket *weston_launch,
int drm_fd,
gboolean master,
GError **error)
meta_launcher_set_master (MetaLauncher *self,
gboolean master,
GError **error)
{
if (weston_launch)
struct weston_launcher_set_master message;
GSocketControlMessage *cmsg;
gboolean ok;
message.header.opcode = WESTON_LAUNCHER_DRM_SET_MASTER;
message.set_master = master;
cmsg = g_unix_fd_message_new ();
if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
self->drm_fd, error) == FALSE)
{
struct weston_launcher_set_master message;
GSocketControlMessage *cmsg;
gboolean ok;
message.header.opcode = WESTON_LAUNCHER_DRM_SET_MASTER;
message.set_master = master;
cmsg = g_unix_fd_message_new ();
if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
drm_fd, error) == FALSE)
{
g_object_unref (cmsg);
return FALSE;
}
ok = send_message_to_wl (weston_launch, &message, sizeof message, cmsg, NULL, error);
g_object_unref (cmsg);
return ok;
return FALSE;
}
else
{
int ret;
if (master)
ret = drmSetMaster (drm_fd);
else
ret = drmDropMaster (drm_fd);
ok = send_message_to_wl (self->weston_launch, &message,
sizeof message, cmsg, NULL, error);
if (ret < 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"Failed to set DRM master directly: %s", strerror (-ret));
return FALSE;
}
else
return TRUE;
}
g_object_unref (cmsg);
return ok;
}
int
meta_weston_launch_open_input_device (GSocket *weston_launch,
const char *name,
int flags,
GError **error)
meta_launcher_open_input_device (MetaLauncher *self,
const char *name,
int flags,
GError **error)
{
if (weston_launch)
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->weston_launch, message, size,
NULL, &cmsg, error);
if (ok)
{
struct weston_launcher_open *message;
GSocketControlMessage *cmsg;
gboolean ok;
gsize size;
int *fds, n_fd;
int ret;
g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
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;
fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
g_assert (n_fd == 1);
ok = send_message_to_wl (weston_launch, 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;
ret = fds[0];
g_free (fds);
g_object_unref (cmsg);
}
else
ret = -1;
g_free (message);
return ret;
}
static void
meta_launcher_finalize (GObject *object)
{
MetaLauncher *launcher = META_LAUNCHER (object);
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_OBJECT_CLASS (meta_launcher_parent_class)->finalize (object);
}
static void
meta_launcher_enter (MetaLauncher *launcher)
{
GError *error;
error = NULL;
if (!meta_launcher_set_master (launcher, TRUE, &error))
{
int ret;
g_critical ("Failed to become DRM master: %s", error->message);
g_error_free (error);
}
ret = open (name, flags, 0);
clutter_evdev_reclaim_devices ();
}
if (ret < 0)
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
"Failed to open input device directly: %s", strerror (errno));
static void
meta_launcher_leave (MetaLauncher *launcher)
{
GError *error;
return ret;
error = NULL;
if (!meta_launcher_set_master (launcher, FALSE, &error))
{
g_critical ("Failed to release DRM master: %s", error->message);
g_error_free (error);
}
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_input_device (launcher, path, flags, error);
}
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;
g_signal_emit (launcher, signals[SIGNAL_LEAVE], 0);
message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
error = NULL;
ok = send_message_to_wl (launcher->weston_launch, &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;
g_signal_emit (launcher, signals[SIGNAL_ENTER], 0);
}
static void
on_socket_readable (GSocket *socket,
GIOCondition condition,
gpointer user_data)
{
MetaLauncher *launcher = user_data;
struct weston_launcher_message header;
gssize read;
GError *error;
if ((condition & G_IO_IN) == 0)
return;
error = NULL;
read = g_socket_receive (socket, (char*)&header, sizeof(header), NULL, &error);
if (read < (gssize)sizeof(header))
{
g_warning ("Error reading from weston-launcher socket: %s", error->message);
g_error_free (error);
return;
}
switch (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;
}
}
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);
}
static void
meta_launcher_init (MetaLauncher *self)
{
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);
clutter_evdev_set_open_callback (on_evdev_device_open, self);
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);
}
static void
meta_launcher_class_init (MetaLauncherClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_launcher_finalize;
klass->enter = meta_launcher_enter;
klass->leave = meta_launcher_leave;
signals[SIGNAL_ENTER] = g_signal_new ("enter",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MetaLauncherClass, enter),
NULL, NULL, /* accumulator */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[SIGNAL_LEAVE] = g_signal_new ("leave",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MetaLauncherClass, leave),
NULL, NULL, /* accumulator */
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
MetaLauncher *
meta_launcher_new (void)
{
return g_object_new (META_TYPE_LAUNCHER, NULL);
}
gboolean
meta_launcher_activate_vt (MetaLauncher *launcher,
int 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->weston_launch, &message,
sizeof (message), NULL, NULL, error);
}
void
meta_launcher_set_drm_fd (MetaLauncher *launcher,
int drm_fd)
{
launcher->drm_fd = drm_fd;
}

View File

@@ -21,36 +21,34 @@
#define META_WESTON_LAUNCH_H
#include <glib-object.h>
#include "weston-launch.h"
/* Keep this in sync with weston-launch */
#define META_TYPE_LAUNCHER (meta_launcher_get_type())
#define META_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_LAUNCHER, MetaLauncher))
#define META_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_LAUNCHER, MetaLauncherClass))
#define META_IS_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_LAUNCHER))
#define META_IS_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_LAUNCHER))
#define META_LAUNCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_LAUNCHER, MetaLauncherClass))
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN,
WESTON_LAUNCHER_DRM_SET_MASTER
};
typedef struct _MetaLauncher MetaLauncher;
typedef struct _MetaLauncherClass MetaLauncherClass;
struct weston_launcher_message {
int opcode;
};
GType meta_launcher_get_type (void) G_GNUC_CONST;
struct weston_launcher_open {
struct weston_launcher_message header;
int flags;
char path[0];
};
MetaLauncher *meta_launcher_new (void);
struct weston_launcher_set_master {
struct weston_launcher_message header;
int set_master;
};
gboolean meta_launcher_activate_vt (MetaLauncher *self,
int number,
GError **error);
gboolean meta_weston_launch_set_master (GSocket *weston_launch,
int drm_fd,
gboolean master,
GError **error);
int meta_weston_launch_open_input_device (GSocket *weston_launch,
const char *name,
int flags,
GError **error);
void meta_launcher_set_drm_fd (MetaLauncher *self,
int drm_fd);
gboolean meta_launcher_set_master (MetaLauncher *self,
gboolean master,
GError **error);
int meta_launcher_open_input_device (MetaLauncher *self,
const char *name,
int flags,
GError **error);
#endif

View File

@@ -301,14 +301,6 @@ xserver_died (GPid pid,
}
}
static int
x_io_error (Display *display)
{
g_error ("Connection to xwayland lost");
return 0;
}
gboolean
meta_xwayland_start (MetaWaylandCompositor *compositor)
{
@@ -430,13 +422,6 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
g_main_loop_run (compositor->init_loop);
/* We install an X IO error handler in addition to the child watch,
because after Xlib connects our child watch may not be called soon
enough, and therefore we won't crash when X exits (and most important
we won't reset the tty).
*/
XSetIOErrorHandler (x_io_error);
return TRUE;
}

View File

@@ -46,6 +46,7 @@
#include <termios.h>
#include <linux/vt.h>
#include <linux/major.h>
#include <linux/kd.h>
#include <pwd.h>
#include <grp.h>
@@ -53,14 +54,18 @@
#include <xf86drm.h>
#ifdef HAVE_SYSTEMD_LOGIN
#include <systemd/sd-login.h>
#endif
#include "weston-launch.h"
#define MAX_ARGV_SIZE 256
enum vt_state {
VT_HAS_VT,
VT_PENDING_CONFIRM,
VT_NOT_HAVE_VT,
};
struct weston_launch {
struct pam_conv pc;
pam_handle_t *ph;
@@ -74,64 +79,26 @@ struct weston_launch {
pid_t child;
int verbose;
char *new_user;
struct termios terminal_attributes;
int kb_mode;
enum vt_state vt_state;
int expect_drop_master;
};
union cmsg_data { unsigned char b[4]; int fd; };
static gid_t *
read_groups(void)
{
int n;
gid_t *groups;
n = getgroups(0, NULL);
if (n < 0) {
fprintf(stderr, "Unable to retrieve groups: %m\n");
return NULL;
}
groups = malloc(n * sizeof(gid_t));
if (!groups)
return NULL;
if (getgroups(n, groups) < 0) {
fprintf(stderr, "Unable to retrieve groups: %m\n");
free(groups);
return NULL;
}
return groups;
}
static void quit (struct weston_launch *wl, int status);
static int
weston_launch_allowed(struct weston_launch *wl)
{
struct group *gr;
gid_t *groups;
int i;
#ifdef HAVE_SYSTEMD_LOGIN
char *session, *seat;
int err;
#endif
if (getuid() == 0)
return 1;
gr = getgrnam("weston-launch");
if (gr) {
groups = read_groups();
if (groups) {
for (i = 0; groups[i]; ++i) {
if (groups[i] == gr->gr_gid) {
free(groups);
return 1;
}
}
free(groups);
}
}
#ifdef HAVE_SYSTEMD_LOGIN
err = sd_pid_get_session(getpid(), &session);
if (err == 0 && session) {
if (sd_session_is_active(session) &&
@@ -142,52 +109,10 @@ weston_launch_allowed(struct weston_launch *wl)
}
free(session);
}
#endif
return 0;
}
static int
pam_conversation_fn(int msg_count,
const struct pam_message **messages,
struct pam_response **responses,
void *user_data)
{
return PAM_SUCCESS;
}
static int
setup_pam(struct weston_launch *wl)
{
int err;
wl->pc.conv = pam_conversation_fn;
wl->pc.appdata_ptr = wl;
err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to start pam transaction: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
err = pam_open_session(wl->ph, 0);
if (err != PAM_SUCCESS) {
fprintf(stderr, "failed to open pam session: %d: %s\n",
err, pam_strerror(wl->ph, err));
return -1;
}
return 0;
}
static int
setup_launcher_socket(struct weston_launch *wl)
{
@@ -221,6 +146,7 @@ setup_signals(struct weston_launch *wl)
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1);
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
assert(ret == 0);
@@ -273,6 +199,11 @@ handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
ret = drmSetMaster(data->fd);
else
ret = drmDropMaster(data->fd);
if (ret == -1)
ret = -errno;
if (message->set_master == 0)
wl->expect_drop_master = 0;
close(data->fd);
@@ -290,6 +221,70 @@ out:
return 0;
}
static int
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
{
int ret = -1;
if (wl->vt_state != VT_PENDING_CONFIRM) {
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
goto out;
}
if (wl->expect_drop_master) {
error(0, 0, "drmDropMaster not called for VT switch");
quit(wl, 1);
}
wl->vt_state = VT_NOT_HAVE_VT;
ioctl(wl->tty, VT_RELDISP, 1);
if (wl->verbose)
fprintf(stderr, "weston-launcher: confirmed VT switch\n");
ret = 0;
out:
do {
len = send(wl->sock[0], &ret, sizeof ret, 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)
{
int ret = -1;
struct weston_launcher_activate_vt *message;
if (len != sizeof(*message)) {
error(0, 0, "missing value in activate_vt request");
goto out;
}
message = msg->msg_iov->iov_base;
ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
if (ret < 0)
ret = -errno;
if (wl->verbose)
fprintf(stderr, "weston-launch: activate VT, ret: %d\n", ret);
out:
do {
len = send(wl->sock[0], &ret, sizeof ret, 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)
{
@@ -395,19 +390,49 @@ handle_socket_msg(struct weston_launch *wl)
case WESTON_LAUNCHER_DRM_SET_MASTER:
ret = handle_setmaster(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)
{
int err;
if (wl->child > 0)
kill(wl->child, SIGKILL);
close(wl->signalfd);
close(wl->sock[0]);
tty_reset(wl);
if (wl->new_user) {
err = pam_close_session(wl->ph, 0);
if (err)
@@ -419,6 +444,32 @@ quit(struct weston_launch *wl, int status)
exit(status);
}
static int
handle_vt_switch(struct weston_launch *wl)
{
struct weston_launcher_message message;
ssize_t len;
if (wl->vt_state == VT_HAS_VT) {
wl->vt_state = VT_PENDING_CONFIRM;
wl->expect_drop_master = 1;
message.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);
message.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
} else
return -1;
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)
{
@@ -455,6 +506,8 @@ handle_signal(struct weston_launch *wl)
if (wl->child)
kill(wl->child, sig.ssi_signo);
break;
case SIGUSR1:
return handle_vt_switch(wl);
default:
return -1;
}
@@ -463,87 +516,102 @@ handle_signal(struct weston_launch *wl)
}
static int
setup_tty(struct weston_launch *wl, const char *tty)
setup_tty(struct weston_launch *wl)
{
struct stat buf;
char *t;
struct termios raw_attributes;
struct vt_mode mode = { 0 };
char *session, *tty;
char path[PATH_MAX];
int ok;
if (!wl->new_user) {
wl->tty = STDIN_FILENO;
} else if (tty) {
t = ttyname(STDIN_FILENO);
if (t && strcmp(t, tty) == 0)
wl->tty = STDIN_FILENO;
else
wl->tty = open(tty, O_RDWR | O_NOCTTY);
} else {
int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
char filename[16];
ok = sd_pid_get_session(getpid(), &session);
if (ok < 0)
error(1, -ok, "could not determine current session");
if (tty0 < 0)
error(1, errno, "could not open tty0");
ok = sd_session_get_tty(session, &tty);
if (ok == 0) {
snprintf(path, PATH_MAX, "/dev/%s", tty);
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
free(tty);
#ifdef HAVE_SD_SESSION_GET_VT
} else if (ok == -ENOENT) {
/* Negative errnos are cool, right?
So cool that we can't distinguish "session not found"
from "key does not exist in the session file"!
Let's assume the latter, as we got the value
from sd_pid_get_session()...
*/
if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
error(1, errno, "failed to find non-opened console");
ok = sd_session_get_vt(session, &tty);
if (ok < 0)
error(1, -ok, "could not determine current TTY");
snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
wl->tty = open(filename, O_RDWR | O_NOCTTY);
close(tty0);
}
snprintf(path, PATH_MAX, "/dev/tty%s", tty);
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
free(tty);
#endif
} else
error(1, -ok, "could not determine current TTY");
if (wl->tty < 0)
error(1, errno, "failed to open tty");
if (tty) {
if (fstat(wl->tty, &buf) < 0)
error(1, errno, "stat %s failed", 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", tty);
if (major(buf.st_rdev) != TTY_MAJOR)
error(1, 0, "invalid tty device: %s", path);
wl->ttynr = minor(buf.st_rdev);
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
setup_session(struct weston_launch *wl)
drop_privileges(struct weston_launch *wl)
{
char **env;
char *term;
int i;
if (wl->tty != STDIN_FILENO) {
if (setsid() < 0)
error(1, errno, "setsid failed");
if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
error(1, errno, "TIOCSCTTY failed - tty is in use");
}
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");
term = getenv("TERM");
clearenv();
setenv("TERM", term, 1);
setenv("USER", wl->pw->pw_name, 1);
setenv("LOGNAME", wl->pw->pw_name, 1);
setenv("HOME", wl->pw->pw_dir, 1);
setenv("SHELL", wl->pw->pw_shell, 1);
env = pam_getenvlist(wl->ph);
if (env) {
for (i = 0; env[i]; ++i) {
if (putenv(env[i]) < 0)
error(0, 0, "putenv %s failed", env[i]);
}
free(env);
}
}
static void
@@ -556,14 +624,11 @@ launch_compositor(struct weston_launch *wl, int argc, char *argv[])
if (wl->verbose)
printf("weston-launch: spawned weston with pid: %d\n", getpid());
if (wl->new_user)
setup_session(wl);
if (wl->tty != STDIN_FILENO)
setenv_fd("WESTON_TTY_FD", wl->tty);
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. */
@@ -571,6 +636,7 @@ launch_compositor(struct weston_launch *wl, int argc, char *argv[])
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
@@ -592,7 +658,6 @@ 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, " -t, --tty Start session on alternative tty\n");
fprintf(stderr, " -v, --verbose Be verbose\n");
fprintf(stderr, " -h, --help Display this help message\n");
}
@@ -602,10 +667,7 @@ main(int argc, char *argv[])
{
struct weston_launch wl;
int i, c;
char *tty = NULL;
struct option opts[] = {
{ "user", required_argument, NULL, 'u' },
{ "tty", required_argument, NULL, 't' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 }
@@ -615,14 +677,6 @@ main(int argc, char *argv[])
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
switch (c) {
case 'u':
wl.new_user = optarg;
if (getuid() != 0)
error(1, 0, "Permission denied. -u allowed for root only");
break;
case 't':
tty = optarg;
break;
case 'v':
wl.verbose = 1;
break;
@@ -635,31 +689,18 @@ main(int argc, char *argv[])
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
error(1, E2BIG, "Too many arguments to pass to weston");
if (strcmp (argv[optind], "mutter") &&
strcmp (argv[optind], "gnome-shell") &&
strcmp (argv[optind], "gnome-shell-real") && 0)
error(1, 0, "mutter-launch can only be used to launch mutter or gnome-shell");
if (strcmp (argv[optind], "mutter-wayland") &&
strcmp (argv[optind], "gnome-shell-wayland"))
error(1, 0, "mutter-launch can only be used to launch mutter or gnome-shell");
if (wl.new_user)
wl.pw = getpwnam(wl.new_user);
else
wl.pw = getpwuid(getuid());
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 should either:\n"
#ifdef HAVE_SYSTEMD_LOGIN
" - run from an active and local (systemd) session.\n"
#else
" - enable systemd session support for weston-launch.\n"
#endif
" - or add yourself to the 'weston-launch' group.");
error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
if (setup_tty(&wl, tty) < 0)
exit(EXIT_FAILURE);
if (wl.new_user && setup_pam(&wl) < 0)
if (setup_tty(&wl) < 0)
exit(EXIT_FAILURE);
if (setup_launcher_socket(&wl) < 0)
@@ -678,8 +719,6 @@ main(int argc, char *argv[])
launch_compositor(&wl, argc - optind, argv + optind);
close(wl.sock[1]);
if (wl.tty != STDIN_FILENO)
close(wl.tty);
while (1) {
struct pollfd fds[2];

View File

@@ -1,5 +1,6 @@
/*
* 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
@@ -25,7 +26,14 @@
enum weston_launcher_opcode {
WESTON_LAUNCHER_OPEN,
WESTON_LAUNCHER_DRM_SET_MASTER
WESTON_LAUNCHER_DRM_SET_MASTER,
WESTON_LAUNCHER_ACTIVATE_VT,
WESTON_LAUNCHER_CONFIRM_VT_SWITCH,
};
enum weston_launcher_server_opcode {
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH,
WESTON_LAUNCHER_SERVER_VT_ENTER,
};
struct weston_launcher_message {
@@ -43,4 +51,9 @@ struct weston_launcher_set_master {
int set_master;
};
struct weston_launcher_activate_vt {
struct weston_launcher_message header;
int vt;
};
#endif

View File

@@ -149,11 +149,9 @@
@serial must match the serial from the last GetResources() call,
or org.freedesktop.DBus.AccessDenied will be generated.
(XXX: a better error maybe?)
If @persistent is true, mutter will attempt to replicate this
configuration the next time this HW layout appears.
(XXX: or is this gnome-settings-daemon role?)
@crtcs represents the new logical configuration, as a list
of structures containing:
@@ -207,11 +205,14 @@
Changes the backlight of @output to @value, which is
expressed as a percentage and rounded to the HW limits.
Returns the new value after rounding.
-->
<method name="ChangeBacklight">
<arg name="serial" direction="in" type="u" />
<arg name="output" direction="in" type="u" />
<arg name="value" direction="in" type="i" />
<arg name="new_value" direction="out" type="i" />
</method>
<!--
@@ -279,5 +280,14 @@
XRandR interface directly).
-->
<property name="PowerSaveMode" type="i" access="readwrite" />
<!--
MonitorsChanged:
The signal is emitted every time the screen configuration
changes.
The client should then call GetResources() to read the new layout.
-->
<signal name="MonitorsChanged" />
</interface>
</node>