Compare commits

...

121 Commits

Author SHA1 Message Date
Florian Müllner
7abc2762e1 Bump version to 3.10.4
Update NEWS.
2014-02-19 19:52:25 +01:00
Ryan Lortie
d59472bb6b idle-monitor: avoid XSyncBadAlarm X error
If we fail to find the IDLETIME counter, then the alarm variable will be
uninitialised.  Most code paths are careful to check this before
submitting XSync calls, but there is one check missing.

https://bugzilla.gnome.org/show_bug.cgi?id=724364
2014-02-15 13:14:54 +01:00
Giovanni Campagna
28d2f36b72 window: don't set _NET_WM_FULLSCREEN_MONITORS to bogus values
Prior to the DisplayConfig merge, we would set _NET_WM_FULLSCREEN_MONITORS
to (unsigned)-1 when unset. After that, we would have invalid
reads inside meta_screen_monitor_index_to_xinerama_index() (called
with -1).
The way I read the specification, the proper way to indicate
that the window is back to fullscreen on all monitors is to
remove the property, so do that.

Also, add an assertion that meta_screne_monitor_index_to_xinerama_index()
is doing the right thing.

https://bugzilla.gnome.org/show_bug.cgi?id=724258
2014-02-13 13:20:35 +01:00
Giovanni Campagna
766181eeae window: fix invalid read in computing the input shape
If we are reported only one rectangle in the input shape, we should
not try to read more.

https://bugzilla.gnome.org/show_bug.cgi?id=724257
2014-02-13 13:20:33 +01:00
Adel Gadllah
5dd2e4bc72 monitorManager: Fix logic bug in make_logical_config
The code that prevents the creation of multiple MonitorInfos for clones
wasn't working due to using the wrong index when getting the already
created info so fix that to use the correct one.

https://bugzilla.gnome.org/show_bug.cgi?id=710610
2014-02-02 15:17:08 +01:00
Adel Gadllah
93ee413df2 window_actor: Remove the frame_messages timeout in destroy
Otherwise it might fire off later and cause a crash.

https://bugzilla.gnome.org/show_bug.cgi?id=723468
2014-02-02 15:17:05 +01:00
Adel Gadllah
06186639fc window-actor: Fix unobscured_region handling when computing paint volume
We currently ignore the unobscured region when we have mapped clones in
meta_window_actor_process_damage and meta_window_actor_damage_all but
use it unconditionally when computing the paint volume.

This is wrong. We should ignore it there as well or we will end up with
empty clones if the cloned window is completly obscured
(like the tray icons in gnome-shell).

https://bugzilla.gnome.org/show_bug.cgi?id=721596
2014-01-31 15:28:42 +01:00
Jasper St. Pierre
5d4138b933 window-actor: Fix optimization in get_paint_volume
We need to clip the paint volume to the unobscured region, not the
other way around...

https://bugzilla.gnome.org/show_bug.cgi?id=720630
2014-01-31 15:28:38 +01:00
Florian Müllner
bafbbc62e2 window: Add "skip-taskbar" property
We currently only have a method to query the skip-taskbar hint.
Add a corresponding property to allow listening for change
notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=723307
2014-01-31 10:11:58 +01:00
Florian Müllner
c3f28b9cdb Bump version to 3.10.1
Update NEWS.
2013-10-15 16:52:03 +02:00
Hans Petter Jansson
dc4e1d4cd1 shaped-texture: Use nearest-pixel interpolation if the texture is unscaled
Use nearest-pixel interpolation if the texture is unscaled. This
improves performance, especially with software rendering.

Bug: https://bugzilla.gnome.org/show_bug.cgi?id=708389
2013-10-10 11:14:05 -04:00
Jasper St. Pierre
d69553e8f5 stack: Never try to focus a DOCK window 2013-10-09 18:10:39 -04:00
Jasper St. Pierre
0ead0d945a prefs: Fix introspection issues 2013-10-09 16:26:45 -04:00
Adel Gadllah
c24d9bf142 meta-window-actor: Fix offset calculation in queue_send_frame_messages_timeout
The current time offset calculation is wrong. It is supposed to calculate
the offset between the current time and the
"time where it message should be sent" (last_time + interval).

Fix the math to actually do that.

https://bugzilla.gnome.org/show_bug.cgi?id=709340
2013-10-07 20:22:53 +02:00
Jasper St. Pierre
a6bf340ff8 display: Deduplicate cursor loading code
Rather than do the cursor -> name translation ourselves in two different
places, use the facilities in libXcursor to do it for us. Put the shared
piece of code in meta-cursor-tracker, and use it for both server-side and
client-side cursor loading.
2013-10-07 13:34:40 -04:00
Jasper St. Pierre
35ef7c95b2 cursor-tracker: Fix the translation for DND_IN_DRAG 2013-10-07 13:09:16 -04:00
Giovanni Campagna
348f3007d9 MetaIdleMonitor: protect the monitor instance while calling destroy notify
The destroy notify for a DBus watch holds a reference to the IdleMonitor,
but the IdleMonitorWatch object doesn't (it knows all watches will
be destroyed before the monitor is, so it doesn't need one). This
means that the DBus watch reference can be the only one keeping
the IdleMonitor alive (expecially true for device idle monitors,
which are only used by g-s-d/cursor), and that means that calling
the destroy notify freezes the monitor (and the next X calls
access garbage).

https://bugzilla.gnome.org/show_bug.cgi?id=708420
2013-09-26 18:57:49 +02:00
Giovanni Campagna
52e2a1226e constraints: don't apply fullscreen workarounds for CSD windows
If you maximize a CSD window on a monitor without struts, it ends
up taking the whole monitor size, but it doesn't mean that the
application wants to fullscreen.

https://bugzilla.gnome.org/show_bug.cgi?id=708718
2013-09-26 16:08:49 +02:00
Giovanni Campagna
58622c0515 MetaCursorTracker: fix compilation in big endian arches
The enum name was wrong.
Patch originally by Dan Horák <dan@danny.cz>

https://bugzilla.gnome.org/show_bug.cgi?id=708813
2013-09-26 13:33:23 +02:00
Giovanni Campagna
cb5e1e2776 Bump version to 3.10.0.1
Update NEWS
2013-09-25 20:00:16 +02:00
Giovanni Campagna
e965cf32d4 MetaWindowActor: fix updates with multiple size changes in one frame
We must set x11_size_changed even if we are frozen, as every window
size change makes the X server drop the pixmap, and we might lose
the information at the next thaw() if the window changes size
twice in one frame (so we would keep drawing with the old pixmap
until something else causes another resize)
2013-09-25 19:23:58 +02:00
Giovanni Campagna
ce5e0b20b5 Bump version to 3.10.0
Update NEWS
2013-09-24 14:09:29 +02:00
Giovanni Campagna
90854a0f80 configure: update dependencies for clutter packages
Make sure that clutter is at the right minimum version for the API
we use, and that it is built with the right configure flags, by
checking for subpackage .pcs too.

https://bugzilla.gnome.org/show_bug.cgi?id=708210
2013-09-20 23:07:49 +02:00
Giovanni Campagna
2d9dc143fc Bump version to 3.9.92
Update NEWS
2013-09-17 10:13:29 +02:00
Giovanni Campagna
1e52d2aa9c Cherry-pick translation updates from master 2013-09-17 10:13:29 +02:00
Giovanni Campagna
2734c8547f Fix distcheck
Remove a warning that makes us fail with -Werror
2013-09-17 09:49:17 +02:00
Giovanni Campagna
cc0b093f7a MonitorConfig: fix hole filling in the laptop lid automatic configuration
Need two passes, because the order we traverse the array is
alphabetical on connector name, not left to right, so we might
see a monitor on the right before we get the offset from disabling
the primary monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=707473
2013-09-16 22:43:07 +02:00
Giovanni Campagna
d25275fa8d MonitorConfig: remove holes generated by disabling the laptop lid
No, holes in the framebuffer are not a good a thing: windows can
get lost there, and the user can get very confused.
Instead, compact the monitors that where previously after.

https://bugzilla.gnome.org/show_bug.cgi?id=707473
2013-09-16 22:43:00 +02:00
Giovanni Campagna
389e04c715 MetaIdleMonitor: fire immediately watches that are already expired
The XSync semantics mandate that alarms already expired will not
fire until the counter is reset and the alarm triggered again, so
clients traditionally called get_idle_time() first to see if they
should install the alarm.
This is inherently racy, as by the time the call is handled by
mutter and the reply received the idle time could be different.
Instead, if we see that the watch would have fired in the past,
fire it immediately.

This is a behavior change, but it's a compatible one, as all legacy
clients are calling get_idle_time() first, and it was perfectly
possible for the idle time counter to trigger the alarm right
after the get_idle_time() call.

https://bugzilla.gnome.org/show_bug.cgi?id=707302
2013-09-16 22:42:22 +02:00
Giovanni Campagna
24074a81d0 mutter-launch: fix for more systemd API changes
Modern systemd changed the semantics of sd_session_get_tty() to
return the full path, rather than just the tty name.

Reviewed by Ray Strode in IRC.
2013-09-16 17:30:45 +02:00
Giovanni Campagna
c0e7f6d9bf wayland: remove some wl_signal usage
It was a left-over from the initial code import from weston.

https://bugzilla.gnome.org/show_bug.cgi?id=707863
2013-09-16 14:51:13 +02:00
Giovanni Campagna
9a13b857f4 wayland: implement stacked popups
Allow multiple popups from the same clients to be stacked under
the same pointer grab.
This is necessary to implement submenus.

https://bugzilla.gnome.org/show_bug.cgi?id=707863
2013-09-16 14:51:13 +02:00
Giovanni Campagna
776a86a65f wayland: heavily refactor pointer grabs
Grabs are now slice allocated structures that are handled by
whoever starts the grab. They contain a generic grab structure
with the interface and a backpointer to the MetaWaylandPointer.
The grab interface has been changed to pass full clutter events,
which allowed to remove the confusion between grab->focus and
pointer->focus. Invidual grabs are now required to keep their
focus, and choose whoever gets the events.

https://bugzilla.gnome.org/show_bug.cgi?id=707863
2013-09-16 14:51:12 +02:00
Giovanni Campagna
76e2455d1b wayland: implement support for popup surfaces
Popup surfaces are mapped into override_redirect surfaces
of a DROPDOWN_MENU type, with the addition of a special pointer
grab.

https://bugzilla.gnome.org/show_bug.cgi?id=707863
2013-09-16 14:51:12 +02:00
Giovanni Campagna
81d9797544 wayland: implement transient hints for wayland clients
wl_shell supports a set_transient() map request that is equivalent
to setting WM_TRANSIENT_FOR in X11, so implement that.

https://bugzilla.gnome.org/show_bug.cgi?id=707401
2013-09-16 14:48:57 +02:00
Giovanni Campagna
12d6c70000 MetaWaylandSurface: cache the surface type until the first commit
Once the sizing is properly wired up, we need to make sure that
the size at the initial map is correct, and not always 0, 0 because
the buffer is not yet converted into a CoglTexture by MetaShapedTexture,
otherwise we end up sending out configure events at 1 x 1.
To do so, we cache the surface type in the initial state until the
first commit.

https://bugzilla.gnome.org/show_bug.cgi?id=707401
2013-09-16 14:46:35 +02:00
Giovanni Campagna
a7eaf43e18 wayland: implement resizing and maximization for wayland clients
To properly resize clients, we need to send them configure events
with the size we computed from the constraint system, and
then check if the new size they ask is compatible with
our expectation.

Note that this does not handle interactive resizing yet, it
merely makes the API calls work for wayland clients.

https://bugzilla.gnome.org/show_bug.cgi?id=707401
2013-09-16 14:46:34 +02:00
Giovanni Campagna
514fec7275 display: include wayland clients in the tab list
Make sure that meta_display_list_windows() returns wayland windows
too, by keeping a separate hash for wayland clients.
This fixes a crash in the alt-tab code of gnome-shell.

Reviewed by drago01 in IRC.
2013-09-16 11:29:36 +02:00
Giovanni Campagna
42a5f4f479 MetaShapedTexture: don't intersect a region with an uninitialized clip
If we skip getting the clip rectangle because we don't have an
allocation or a texture, don't intersect with the visible region.
This avoids a pixman warning of an invalid rectangle.

Reviewed by drago01 in IRC.
2013-09-16 11:28:12 +02:00
Giovanni Campagna
6c1feedbdf Fixup previous MetaCursorTracker commit
I had it fixed locally, then it was lost in a bad rebase.
2013-09-16 10:06:44 +02:00
Giovanni Campagna
2d21fbbd35 wayland: disable extended barriers support
We don't have actual pointer barriers implemented, so this is a
quick workaround to trigger the fallback paths in the shell, for
the hot corner and the message tray.
To be reverted after 3.10
2013-09-16 09:34:27 +02:00
Giovanni Campagna
7baf687499 MetaCursorTracker: add support for loading cursors from the theme
Not only this way we get the right Adwaita cursor as the default
(instead of shipping our own in png format), but we also add
support for all MetaCursors as root cursor (which most important
should allow us to have I-beams in shell entries)

https://bugzilla.gnome.org/show_bug.cgi?id=707573
2013-09-16 09:31:44 +02:00
Giovanni Campagna
a3e44d13d1 wayland: implement HW cursors
Use the DRM API and libgbm to upload cursor buffers to the
appropriate HW plane, saving on GL calls and compositing.

https://bugzilla.gnome.org/show_bug.cgi?id=707573
2013-09-16 09:27:48 +02:00
Giovanni Campagna
65db8efbe8 MonitorManager: add a KMS backend
Using the new Cogl API to actually modeset (because we can't
use the DRM API directly without controlling buffer swap), we
can finally have a KMS monitor backend, which means full display
configuration when running on bare metal.

https://bugzilla.gnome.org/show_bug.cgi?id=706308
2013-09-16 00:34:48 +02:00
Adel Gadllah
e48a5cd5f2 mutter-launch: Use the correct binary name for the help message as well 2013-09-15 20:28:24 +02:00
Adel Gadllah
698bb24848 mutter-launch: Use correct binary name in error messages 2013-09-15 20:25:39 +02:00
Pavel Vasin
67fff237e6 MonitorConfig: fix memory leak
https://bugzilla.gnome.org/show_bug.cgi?id=708070
2013-09-14 17:07:32 +02:00
Pavel Vasin
b9247b4b2f shaped-texture: Fix memory leak
https://bugzilla.gnome.org/show_bug.cgi?id=708070
2013-09-14 17:07:32 +02:00
Pavel Vasin
0394b4a82b window: Fix memory leak
https://bugzilla.gnome.org/show_bug.cgi?id=708070
2013-09-14 17:07:32 +02:00
Pavel Vasin
ff7c85c599 workspace: Add missing chain-up for finalize()
https://bugzilla.gnome.org/show_bug.cgi?id=708070
2013-09-14 17:07:32 +02:00
Kalev Lember
c316ad17a4 Drop man pages for removed utilities
Commit 8c1c77482d removed mutter-message,
mutter-theme-viewer, and mutter-theme-viewer; this drops their man pages
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=706579
2013-09-12 13:26:34 +02:00
Giovanni Campagna
fc108d5052 Fixup previous commit
Had a wrong cursor name.
2013-09-12 10:33:26 +02:00
Giovanni Campagna
8c0d38a1a1 display: add support for more cursor types
These cursors are used by gnome-shell, supporting them allows
to reduce GDK usage in the shell.

Also, make meta_screen_set_cursor() public.

https://bugzilla.gnome.org/show_bug.cgi?id=707919
2013-09-12 10:18:20 +02:00
Giovanni Campagna
2f9c6c4146 mutter-launch: adapt to systemd API change
The API was changed during the patch review.

(Yes, we were depending on API which was sitting in a patch not
yet reviewed... you know, vertical integration!)

https://bugzilla.gnome.org/show_bug.cgi?id=707929
2013-09-11 20:36:38 +02:00
Giovanni Campagna
72ca2b218d wayland: die when gnome-session asks us to
At logout, we want to die when gnome-session tells us. Previously,
we were relying on the X server going down (killed by GDM at the
end of the session), but we can't use that in wayland.

https://bugzilla.gnome.org/show_bug.cgi?id=706421
2013-09-11 16:01:24 +02:00
Giovanni Campagna
7360aece74 wayland: don't require Clutter backend variables to be set from outside
When running under mutter-launch, we can assume we're running on
bare metal, and set the clutter backend appropriately.

https://bugzilla.gnome.org/show_bug.cgi?id=706421
2013-09-11 16:01:09 +02:00
Giovanni Campagna
b5f3238f6f Stop messing with process groups
We can be launched by gnome-session now, which implies gdb must be
attached from outside, and the Ctrl-C problem is gone.

https://bugzilla.gnome.org/show_bug.cgi?id=706421
2013-09-11 16:01:09 +02:00
Giovanni Campagna
227fb56103 Set DISPLAY and WAYLAND_DISPLAY for dbus activated services and for autostarted apps
Call the appropriate method on gnome-session so that autostarted
and bus activated apps see the X server and wayland socket.

https://bugzilla.gnome.org/show_bug.cgi?id=706421
2013-09-11 16:01:09 +02:00
Giovanni Campagna
5ae52473c9 Don't translate debug logs and warnings
Warnings that are going to the journal should be not translated:
they're not user visible, and translating them would just make
bug reporting harder (as now the developers need to understand
what the warning is saying)

https://bugzilla.gnome.org/show_bug.cgi?id=707897
2013-09-11 16:01:09 +02:00
Giovanni Campagna
7b537d6b8f Fix regression in mutter-wayland translations
Switching meta/util.h to gi18n.h was wrong, mutter is a library
and needs gi18n-lib.h, but that cannot be included from a public
header (since it depends on config.h or command line options),
so split util.h into a public and a private part.

https://bugzilla.gnome.org/show_bug.cgi?id=707897
2013-09-11 16:01:07 +02:00
Giovanni Campagna
4494888b82 Add an option to run as a wayland compositor
Move the option from the mutter binary to libmutter, and
rename from --nested to --wayland.
This allows gnome-shell to drop the set_is_wayland_compositor()
call.

https://bugzilla.gnome.org/show_bug.cgi?id=707897
2013-09-11 16:00:47 +02:00
Giovanni Campagna
004ee2d3b5 MetaPluginManager: don't require plugins to pass events to clutter
We don't want the shell to know if it's running on ClutterX11 or
not, so we should forward the event ourselves.

https://bugzilla.gnome.org/show_bug.cgi?id=707482
2013-09-10 17:26:15 +02:00
Giovanni Campagna
168ea64a45 wayland: use symbolic constants for interface version
Replace magic numbers scattered around the code with proper
macros collected in one header file.

https://bugzilla.gnome.org/show_bug.cgi?id=707851
2013-09-10 15:55:11 +02:00
Giovanni Campagna
73ee491281 wayland: fix interface versioning
Add MIN(...) with the interface version actually implemented
to all resource constructor, so that we never risk seeing requests
we don't implement (and consequently segfault)

https://bugzilla.gnome.org/show_bug.cgi?id=707851
2013-09-10 15:54:42 +02:00
Giovanni Campagna
95a9655412 wayland: fix deprecation warnings
Replace the deprecated APIs with the modern variants (which
also give us full control on the versioning).
Also, note that we only support version 2 of wl_seat. Version
3 is for multiple pointer/keyboards for a client, but
we don't implement that yet. If a client requests version 3
of wl_seat or make a version 3 request, it will get a protocol error.

https://bugzilla.gnome.org/show_bug.cgi?id=707851
2013-09-10 15:54:37 +02:00
Giovanni Campagna
72b6699efb util: fix warnings when compiling gnome-shell-wayland
Replace our version of the gettext macros with those in glib,
so that they don't conflict with gnome-shell.

https://bugzilla.gnome.org/show_bug.cgi?id=707851
2013-09-10 13:47:30 +02:00
Giovanni Campagna
3e341e83d9 mutter-launch: remove PAM usage
Left-overs from the weston-launch import

https://bugzilla.gnome.org/show_bug.cgi?id=707584
2013-09-09 18:09:08 +02:00
Giovanni Campagna
5b3340e585 MetaCursorTracker: add methods for setting the cursor visibility
clutter_stage_show_cursor()/hide_cursor() only works in the X11
backend (where someone else is in charge of showing the cursor),
and even then, it has confusing effects when running nested wayland,
so an abstraction layer is needed.

https://bugzilla.gnome.org/show_bug.cgi?id=707474
2013-09-09 18:04:07 +02:00
Giovanni Campagna
6f4f611ba8 MetaCursorTracker: extend with query pointer abilities
We need an abstraction in gnome-shell for XQueryPointer, and
MetaCursorTracker seems a good place for it.

https://bugzilla.gnome.org/show_bug.cgi?id=707474
2013-09-09 18:04:07 +02:00
Giovanni Campagna
450afbaf51 wayland: reimplement keyboard state handling properly
We can't rely on clutter's xkb_state, because that's updated
when events are pulled from the kernel, not when we see them.
Instead, use the new clutter API to get the full modifier state
from the event (which, as a side effect, also works when clutter
is using the X11 backend for running nested).

https://bugzilla.gnome.org/show_bug.cgi?id=706963
2013-09-09 17:59:45 +02:00
Giovanni Campagna
28708e4317 MetaWaylandSeat: don't use use events to count pressed buttons
Use the modifier mask instead, as events can get lost if there
is a clutter grab or if some other actor is capturing events.

https://bugzilla.gnome.org/show_bug.cgi?id=706124
2013-09-09 17:59:45 +02:00
Giovanni Campagna
9f64f2cf4f Rename META_POWER_SAVE_UNKNOWN to UNSUPPORTED
It conveys more clearly what this value means.

https://bugzilla.gnome.org/show_bug.cgi?id=707649
2013-09-09 15:33:53 +02:00
Giovanni Campagna
2b1eb206d3 Monitor: don't shortcut set_power_save if the value is the same as the old one
We don't get notifications from X11 when the mode is reset, so
our cached value can get stale. To work around that, always forward
requests to the backend (and let it deal with ignoring the change
if wanted)

https://bugzilla.gnome.org/show_bug.cgi?id=707649
2013-09-09 15:33:53 +02:00
Giovanni Campagna
a6dc454c49 wayland: constraint the pointer onto visible monitors when running on evdev
Use the new Clutter hook to make sure the pointer never enters
the dead area caused by the different monitor sizes.

You don't realize how much X is doing for you until you lose it...

https://bugzilla.gnome.org/show_bug.cgi?id=706655
2013-09-09 12:08:47 +02:00
Giovanni Campagna
c2bf44fa19 Bump version to 3.9.91
Update NEWS
2013-09-05 11:01:53 +02:00
Adel Gadllah
2d67b01c3a window-actor: Use more conservative paint volume
We know which part of the window is not obscured, so take advantaged of that
to limit the size of the paint volume that we report.
2013-09-04 20:08:24 +02:00
Neil Roberts
6014d31dea Don't create a dummy texture for the texture pipeline template
The meta_create_texture_pipeline function used to create a dummy 1x1
texture so that it could make sure that the all of the state that
affects the shader generation would be set on the template pipeline so
that Cogl could share the pipeline's shader with any other pipelines
that are just rendering a texture. This is no longer necessary because
the only thing that affects the shader generation is the texture type,
not the actual texture data and Cogl now has a function to explicitly
set the texture type which we can use instead. Additionally even if
the template mechanism is not used at all Cogl will still end up
reusing the same shader because it now has a shader cache which is
indexed by the pipeline state so pipeline's don't strictly need to
share ancestry in order to take advantage of it. However we still
might as well use the function because if there is a common ancestry
it is faster to look up the shader because Cogl doesn't need to hash
the pipeline state.

https://bugzilla.gnome.org/show_bug.cgi?id=707458
(cherry picked from commit c5bf60eab4)
2013-09-04 15:29:04 +01:00
Jasper St. Pierre
bf78f067a2 Make sure to always call va_end 2013-09-03 16:10:10 -04:00
Jasper St. Pierre
ddb9929dad compositor: Remove some uninitialized variables 2013-09-03 16:10:10 -04:00
Jasper St. Pierre
2098ec2d16 theme-parser: Remove a duplicate paste
How did this sneak in there?
2013-09-03 16:10:10 -04:00
Jasper St. Pierre
97eece6607 display: Add some missing breaks
If we somehow get an event with a wrong device ID, we should not
be comparing bad event IDs.
2013-09-03 16:10:10 -04:00
Ray Strode
7ac9a6e241 compositor: initial has_window to FALSE in sync_actor_stacking
Spotted by Jasper, discussed on IRC.
2013-09-03 16:09:05 -04:00
Giovanni Campagna
b53bf0e8c2 Fix distcheck
Missing translation files, missing dists and some -Werrors.
2013-09-03 17:00:18 +02:00
Giovanni Campagna
a26ded47d9 Add a private gtk-mutter protocol
Add a new interface, gtk_shell, than can be used by gtk to
retrieve a surface extension called gtk_surface, which will be
used to communicate with mutter all the GTK extensions to EWMH

https://bugzilla.gnome.org/show_bug.cgi?id=707128

Add support for GTK application menus

To do so, we need to be able to set surface state before creating
the MetaWindow, so we introduce MetaWaylandSurfaceInitialState as
a staging area.
The gtk-shell-surface implementation would either write to the
initial state, or directly to the window.

At the same, implement set_title and set_class too, because it's
easy enough.

https://bugzilla.gnome.org/show_bug.cgi?id=707128
2013-09-03 10:57:28 -04:00
Giovanni Campagna
cad9e14463 Move surface state tracking and surface interface to a separate file
Move everything surface related from meta-wayland.c to meta-wayland-surface.c

https://bugzilla.gnome.org/show_bug.cgi?id=707128
2013-09-03 10:57:28 -04:00
Giovanni Campagna
806d5939e3 wayland: split headers and distribute structure definitions
Instead of having all structures in one huge headers, move them
in the appropriate place, and create one header for surface state.

https://bugzilla.gnome.org/show_bug.cgi?id=707128
2013-09-03 10:57:28 -04:00
Giovanni Campagna
0f0c23fbab wayland: generalize ShellSurface to SurfaceExtension
We want to implement new shells and new extension interfaces
for wl_surface, so generalize the book-keeping structures.

https://bugzilla.gnome.org/show_bug.cgi?id=707128
2013-09-03 10:57:28 -04:00
Jasper St. Pierre
5d1fcc26c0 Update .gitignore 2013-09-03 10:57:28 -04:00
Giovanni Campagna
cbe5b6b3bc meta-wayland: intersect the damage region with the window size before applying
According to the wayland documentation, damage outside the
window size is ignored.
This happened with xwayland+wlshm (causing a GL error when calling
TexSubImage2D), probably due to not resizing the buffer
until we receive the corresponding X event.
Might also be an off-by-one in xwayland, as the window size did
not actually change.

Note: we might want to take the configure_notify path instead,
and keep the GL/clutter size consistent with wayland rather than
X, because in the end that's what matters for events and composition.

https://bugzilla.gnome.org/show_bug.cgi?id=706289
2013-09-03 10:16:47 -04:00
Giovanni Campagna
590cf4e832 MonitorXrandr: check the event timestamps before reconfiguring
If, checking the event timestamps, we see that a new configuration
was explicitly requested by an another XRandR client, don't proceed to
apply the intended configuration again, even if looking at the
EDIDs it appears that the outputs changed.
This works around some buggy Xorg drivers (qxl, vbox) that generate
a new serial number everytime the user resizes the host window.

https://bugzilla.gnome.org/show_bug.cgi?id=706735
2013-09-02 17:36:03 +02:00
Cosimo Cecchi
22ca820c44 idle-monitor: fix event propagation to devices
device_id_max is set to the device_id in ensure_device_monitor(), but we
will loop only to (device_id_max - 1) when propagating the sync XEvent
down, missing the device correspondng to device_id_max.

https://bugzilla.gnome.org/show_bug.cgi?id=707250
2013-09-01 17:51:10 -07:00
Jasper St. Pierre
b1206ceb66 wayland: Ensure that opaque / input regions are set at commit time
The protocol specification says that opaque / input regions should be
considered pending state and should only be actually swapped out when
the surface is committed, so it can be set atomically.
2013-08-31 13:29:02 -04:00
Giovanni Campagna
ad4053ab84 wayland: fix pointer focus for destroyed surfaces
We had an assertion in meta_wayland_surface_free() that after
a repick() we would not choose the freed surface, but that didn't
consider surfaces destroyed while holding the implicit pointer
grab (ie, because the user clicked on the X button). In that case,
we need to bypass the grab infrastructure and explicitly unfocus
the dead surface.

https://bugzilla.gnome.org/show_bug.cgi?id=706982
2013-08-30 16:07:00 +02:00
Colin Walters
7bd4e6ecb0 weston-launch: Don't segfault if passed no arguments
Probably not exploitable since I think Linux always puts NULL there,
but let's actually check.
2013-08-30 08:26:31 -04:00
Giovanni Campagna
deeb1db1ac wayland: don't free surfaces that have a window associated
After a MetaWaylandSurface is associated with a MetaWindow, it
should be freed only when the MetaWindow is unmanaged. For wayland
clients, the window is unmanaged when the resource is destroyed,
but for X11 clients we want to wait for the unmap event.

https://bugzilla.gnome.org/show_bug.cgi?id=705917
2013-08-30 10:37:25 +02:00
Giovanni Campagna
7eb4bfbea3 wayland: implement support for plugin modality
Calling XIGrabDevice has no effect under wayland, because the
xserver is getting events from us. Instead, we need to use our
own interfaces for grabs.
At the same time, we can simplify the public API, as plugins
should always listen for events using clutter.

https://bugzilla.gnome.org/show_bug.cgi?id=705917
2013-08-30 10:37:25 +02:00
Giovanni Campagna
59b274f12f MetaWaylandKeyboard: use the new clutter-evdev support for xkbcommon
We need to track the full xkb_state to have the necessary information
to send to the clients, otherwise they may get confused and lock
or invert the modifiers. In the evdev backend, we just retrieve the
same state object that clutter is using, while in the other backends
we fake the state using what clutter is providing (which is a subset
of what X11 provides, which would be necessary to have full state)

https://bugzilla.gnome.org/show_bug.cgi?id=705862
2013-08-30 10:37:25 +02:00
Giovanni Campagna
e311cef013 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-30 10:32:55 +02:00
Giovanni Campagna
e72f81c24f 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-30 10:32:55 +02:00
Giovanni Campagna
96fa518576 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,
including the calls to drmSetMaster and drmDropMaster as appropriate.
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-30 10:32:55 +02:00
Giovanni Campagna
e263b3624c 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-30 10:32:55 +02:00
Giovanni Campagna
1c34f0b342 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-30 10:32:55 +02:00
Giovanni Campagna
2d27873f98 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-30 10:32:55 +02:00
Giovanni Campagna
fd40a12213 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-30 10:32:55 +02:00
Jasper St. Pierre
57406e0a9e shaped-texture: Actually fetch rectangles from the blended_region
We checked for the blended region but actually fetched rectangles from
the clip region.
2013-08-29 18:35:18 -04:00
Jasper St. Pierre
1987cbb764 window-actor: Fix build 2013-08-29 17:16:15 -04:00
Jasper St. Pierre
705978405b shaped-texture: Fix build 2013-08-29 17:14:11 -04:00
Adel Gadllah
daba05f6a7 background: Rename visible_region to clip_region
This does better reflect what this region is used for.

https://bugzilla.gnome.org/show_bug.cgi?id=703332
2013-08-29 17:08:57 -04:00
Jasper St. Pierre
1a7984be43 window-actor: Use g_clear_pointer 2013-08-29 17:05:41 -04:00
Jasper St. Pierre
1b3c77d53a shaped-texture: Remove an unnecessary set to NULL 2013-08-29 17:05:36 -04:00
Jasper St. Pierre
5b0f0d9e5b shaped-texture: Remove bad comment
We do not assume ownership of the clip region anymore.
2013-08-29 17:04:55 -04:00
Adel Gadllah
9816659fa9 meta-window-actor: Fix spacing 2013-08-29 17:04:50 -04:00
Adel Gadllah
3b1b611634 meta-window-actor: Throttle obscured frame synced apps
We must send frame_drawn and frame_timing messages to even when
we don't actually queue a redraw on screen to comply with the
WM sync spec.

So throttle such apps to down to a ~100ms interval.

https://bugzilla.gnome.org/show_bug.cgi?id=703332
2013-08-29 17:04:36 -04:00
Adel Gadllah
f08921bd0c meta-shaped-texture: Don't queue redraws for obscured regions
When we get a damage event we update the window by calling
meta_shaped_texture_update_area which queues a redraw on the actor.
We can avoid that for obscured regions by comparing the damage area to
our visible area.

This patch causes _NET_WM_FRAME_DRAWN messages to be not sent in some cases
where they should be sent; they will be added back in a later commit.

https://bugzilla.gnome.org/show_bug.cgi?id=703332
2013-08-29 17:03:48 -04:00
Jasper St. Pierre
0089b5769c shaped-texture: Turn blending off when drawing entirely opaque regions
When drawing entirely opaque regions, we traditionally kept blending on
simply because it made the code more convenient and obvious to handle.
However, this can cause lots of performance issues on GPUs that aren't
too powerful, as they have to readback the buffer underneath.

Keep track of the opaque region set by windows (through _NET_WM_OPAQUE_REGION,
Wayland opaque_region hints, standard RGB32 frame masks or similar), and draw
those rectangles separately through a different path with blending turned off.

https://bugzilla.gnome.org/show_bug.cgi?id=707019
2013-08-29 15:31:53 -04:00
Jasper St. Pierre
452be05ea0 shaped-texture: Use non-deprecated cogl APIs
https://bugzilla.gnome.org/show_bug.cgi?id=707019
2013-08-29 15:31:53 -04:00
Jasper St. Pierre
69f038f7c7 shaped-texture: Simplify pipeline creation
Split out pipeline creation to a separate function so that we don't
have so much dense code in the paint function itself, and remove some
indentation levels.

Also, don't use our own template for the unmasked pipeline, since it
has nothing different from the default pipeline template.

We also don't store the pipelines anymore since their creation isn't
really helping us; we set the mask texture and paint texture on every
paint anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=707019
2013-08-29 15:31:52 -04:00
Jasper St. Pierre
2d35e07fae wayland: Add support for set_opaque_region / set_input_region
https://bugzilla.gnome.org/show_bug.cgi?id=707019
2013-08-29 15:31:52 -04:00
Jasper St. Pierre
95e2d26d03 window-actor: Mark all Wayland clients as argb32
https://bugzilla.gnome.org/show_bug.cgi?id=707019
2013-08-29 15:26:49 -04:00
Jasper St. Pierre
f506e090ea monitor: Use a more sane dummy configuration for nested mode 2013-08-29 15:26:49 -04:00
Jasper St. Pierre
0697b53826 wayland-private: Remove unused buffer fields 2013-08-28 15:28:34 -04:00
110 changed files with 12363 additions and 6916 deletions

11
.gitignore vendored
View File

@@ -48,10 +48,11 @@ po/*.pot
50-metacity-key.xml
libmutter-wayland.pc
mutter-wayland
mutter-theme-viewer
mutter-wayland.desktop
mutter-launch
org.gnome.mutter.gschema.valid
org.gnome.mutter.gschema.xml
org.gnome.mutter.wayland.gschema.valid
org.gnome.mutter.wayland.gschema.xml
testasyncgetprop
testboxes
testgradient
@@ -77,6 +78,12 @@ src/stamp-mutter-marshal.h
src/meta-dbus-xrandr.[ch]
src/meta-dbus-idle-monitor.[ch]
src/mutter-plugins.pc
src/wayland/gtk-shell-protocol.c
src/wayland/gtk-shell-client-protocol.h
src/wayland/gtk-shell-server-protocol.h
src/wayland/xserver-protocol.c
src/wayland/xserver-client-protocol.h
src/wayland/xserver-server-protocol.h
doc/reference/*.args
doc/reference/*.bak
doc/reference/*.hierarchy

View File

@@ -1,5 +1,5 @@
SUBDIRS=src protocol data po doc
SUBDIRS=src protocol po doc
EXTRA_DIST = HACKING MAINTAINERS rationales.txt

100
NEWS
View File

@@ -1,3 +1,103 @@
3.10.4
======
* Expose MetaWindow:skip-taskbar property [Florian; #723307]
* Fix legacy tray icons showing up blank [Adel; #721596]
* Fix configuration of cloned monitors [Adel; #710610]
* Misc. bug fixes [Jasper, Adel, Giovanni; #720630, #723468, #724257, #724258,
#724364]
Contributors:
Giovanni Campagna, Adel Gadllah, Ryan Lortie, Florian Müllner,
Jasper St. Pierre
3.10.1
======
* Don't apply fullscreen workarounds to CSD windows [Giovanni; #708718]
* Fix hangs during DND operations [Adel; #709340]
* Misc bug fixes [Dan, Giovanni, Jasper; #708813, #708420]
Contributors:
Giovanni Campagna, Adel Gadllah, Dan Horák, Hans Petter Jansson,
Jasper St. Pierre
3.10.0.1
========
* Fix bug when a window changed size twice in a single frame - this
can happen with GTK+ client-side decorations [Giovanni, Owen; #708367]
Contributors:
Giovanni Campagna, Owen Taylor
3.10.0
======
* Update dependencies [Giovanni; #708210]
3.9.92
======
* Constrain the pointer position onto visible monitors [Giovanni; #706655]
* Fix keyboard state handling in face of event compression [Giovanni; #706963]
* Extend the MetaCursorTracker API with query pointer and cursor visibility [Giovanni; #707474]
* Be stricter in checking and exposing the wayland protocol version [#707851]
* Don't require plugins to pass event to Clutter [Giovanni; #707482]
* Move the --wayland option from the binary to the library [Giovanni; #707897]
* Implement running from gnome-session (environment variable setting, process group
handling, Clutter backend variables) [Giovanni; #706421]
* Add support for more cursor types [Giovanni; #707919]
* Drop man pages for removed utilities [Kalev; #706579]
* Implement monitor configuration on KMS [Giovanni; #706308]
* Implement HW cursors [Giovanni; #707573]
* Implement minimal support for resizing and maximizing wayland clients [Giovanni; #707401]
* Implement transient hints for wayland clients [Giovanni; #707401]
* Implement popup menu surfaces and grabs [Giovanni; #707863]
* Immediately fire idle watches that are already expired [Giovanni; #707302]
* Remove holes generated by disabling the laptop lid [Giovanni; #707473]
* Misc bug fixes [Giovanni, Pavel, Adel; #707649, #706124, #707584, #707851, #707929,
#708070]
Contributors:
Adel Gadllah, Giovanni Campagna, Kalev Lember, Pavel Vasin
Translations:
Мирослав Николић po/sr, sr@latin.po, Мирослав Николић [sr, sr@latin],
Chao-Hsiung Liao [zh_HK, zh_TW], Yuri Myasoedov [ru],
Ville-Pekka Vainio [fi], Changwoo Ryu [ko], A S Alam [pa],
Mattias Põldaru [et], Rūdolfs Mazurs [lv], Ihar Hrachyshka [be],
Nilamdyuti Goswami [as], Andika Triwidada [id], Baurzhan Muftakhidinov [kk],
Benjamin Steinwender [de]
3.9.91
======
* Drop man pages for removed utilities [Kalev; #706579]
* Add support for idle tracking [Giovanni, Cosimo; #706005, #707250]
* Skip CRTC reconfigurations that have no effect [Giovanni; #706672]
* Ignore skip-taskbar hints on parentless dialogs [Giovanni; #673399]
* Don't save pixbuf data in user data [Tim; #706777]
* Don't queue redraws for obscured regions [Adel; #703332]
* Suppor the opaque region hints for wayland clients [Jasper; #707019]
* Turn blending off when drawing entirely opaque regions [Jasper; #707019]
* Check event timestamps before reconfiguring [Giovanni; #706735]
* Merge the DBus API for display configuration in the wayland branch [Giovanni]
* Install an X IO error handler for XWayland [Giovanni; #706962]
* Use the clutter xkbcommon integration for the wayland keyboard [Giovanni; #705862]
* Add a setuid helper for running on KMS+evdev [Giovanni, Colin; #705861]
* Add keybindings for switching VT [Giovanni; #705861]
* Implement plugin modality when running as a wayland compositor [Giovanni; #705917]
* Add support for the application menu for wayland clients [Giovanni; #707128]
* Several Coverity spotted fixes [Jasper]
* Don't create a dummy texture for the texture template [Neil; #707458]
* Use a more conservative paint volume for obscured windows [Adel]
* Misc bug fixes [Giovanni, Colin, Seán, Jasper, Cosimo; #706582, #706598,
#706787, #706729, #706825, #707081, #707090, #707267, #706982, #706289]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Adel Gadllah, Colin Guthrie, Kalev Lember,
Tim Lunn, Jasper St. Pierre, Neil Roberts, Rico Tzschichholz, Seán de Búrca
Translations:
Piotr Drąg [pl], Alexandre Franke [fr], Kjartan Maraas [nb],
Milo Casagrande [it], Balázs Úr [hu], Seán de Búrca [ga], Fran Diéguez [gl],
Daniel Mustieles [es], Aurimas Černius [lt], Gil Forcada [ca]
3.9.90
======
* First release from the wayland branch, includes basic support for running

View File

@@ -1,8 +1,8 @@
AC_PREREQ(2.50)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [9])
m4_define([mutter_micro_version], [90])
m4_define([mutter_minor_version], [10])
m4_define([mutter_micro_version], [4])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -77,7 +77,7 @@ MUTTER_PC_MODULES="
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.14.3
$CLUTTER_PACKAGE >= 1.15.94
cogl-1.0 >= 1.13.3
upower-glib > 0.9.11
gnome-desktop-3.0
@@ -139,6 +139,12 @@ AM_GLIB_GNU_GETTEXT
## here we get the flags we'll actually use
# GRegex requires Glib-2.14.0
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
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"
@@ -203,19 +209,7 @@ if test x$found_introspection != xno; then
AC_SUBST(META_GIR)
fi
AC_MSG_CHECKING([Xcursor])
if $PKG_CONFIG xcursor; then
have_xcursor=yes
else
have_xcursor=no
fi
AC_MSG_RESULT($have_xcursor)
if test x$have_xcursor = xyes; then
echo "Building with Xcursor"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
AC_DEFINE(HAVE_XCURSOR, , [Building with Xcursor support])
fi
MUTTER_PC_MODULES="$MUTTER_PC_MODULES xcursor"
# We always build with wayland enabled
AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
@@ -226,7 +220,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
AC_SUBST([WAYLAND_SCANNER])
AC_SUBST(XWAYLAND_PATH)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server"
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm"
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
@@ -467,7 +461,6 @@ src/Makefile
src/libmutter-wayland.pc
src/compositor/plugins/Makefile
protocol/Makefile
data/Makefile
po/Makefile.in
])

View File

@@ -1,3 +0,0 @@
defaultcursordir = $(pkgdatadir)/cursors
dist_defaultcursor_DATA = left_ptr.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 736 B

View File

@@ -1,4 +1,3 @@
man_MANS = mutter.1 mutter-theme-viewer.1 \
mutter-window-demo.1 mutter-message.1
man_MANS = mutter.1
EXTRA_DIST = $(man_MANS)

View File

@@ -1,60 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.\" -----
.\" This file was confirmed to be licenced under the GPL
.\" by its author and copyright holder, Akira TAGOH, on June 1st 2008:
.\"
.\" > I'm comfortable with DFSG-free. that sounds great if you think it's
.\" > useful and worth containing it in upstream.
.\" ...
.\" > Right I know. any licenses that is DFSG-free, I'm ok with whatever,
.\" > since I have contributed that for Debian. so GPL is no problem for me.
.\" -----
.TH MUTTER\-MESSAGE 1 "28 August 2002"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
MUTTER\-MESSAGE \- a command to send a message to Mutter
.SH SYNOPSIS
.B MUTTER\-MESSAGE
[restart|reload\-theme|enable\-keybindings|disable\-keybindings]
.SH DESCRIPTION
This manual page documents briefly the
.B mutter\-message\fP.
This manual page was written for the Debian distribution
because the original program does not have a manual page.
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
\fBmutter\-message\fP send a specified message to \fBmutter\fP(1).
.SH OPTIONS
.TP
.B restart
Restart \fBmutter\fP(1) which is running.
.TP
.B reload-theme
Reload a theme which is specified on gsettings database.
.TP
.B enable-keybindings
Enable all of keybindings which is specified on gsettings database.
.TP
.B disable-keybindings
Disable all of keybindings which is specified on gsettings database.
.SH SEE ALSO
.BR mutter (1)
.SH AUTHOR
This manual page was written by Akira TAGOH <tagoh@debian.org>,
for the Debian GNU/Linux system (but may be used by others).

View File

@@ -1,43 +0,0 @@
.\" In .TH, FOO should be all caps, SECTION should be 1-8, maybe w/ subsection
.\" other parms are allowed: see man(7), man(1)
.\"
.\" Based on template provided by Tom Christiansen <tchrist@jhereg.perl.com>.
.\"
.TH MUTTER-THEME-VIEWER 1 "1 June 2004"
.SH NAME
mutter-theme-viewer \- view mutter themes
.SH SYNOPSIS
.B mutter-theme-viewer
[
.I THEMENAME
]
.SH DESCRIPTION
.\" Putting a newline after each sentence can generate better output.
.B mutter-theme-viewer
allows you to preview any installed Mutter theme.
.PP
When designing a new Mutter theme, you can use
.B mutter-theme-viewer
to measure the performance of a window frame option, and to preview
the option.
.SH OPTIONS
.TP
.I THEMENAME
Name of the theme to be shown (\fIAtlanta\fR by default).
It is case-sensitive.
.SH FILES
.br
.nf
.TP
.I /usr/share/themes
system themes directory
.TP
.I /usr/share/themes/*/mutter-1/mutter-theme-1.xml
theme specification file
.SH AUTHOR
This manual page was written by Jose M. Moya <josem@die.upm.es>, for
the Debian GNU/Linux system (but may be used by others).
.SH "SEE ALSO"
.\" Always quote multiple words for .SH
.BR mutter (1),
.BR mutter-window-demo (1).

View File

@@ -1,25 +0,0 @@
.\" In .TH, FOO should be all caps, SECTION should be 1-8, maybe w/ subsection
.\" other parms are allowed: see man(7), man(1)
.\"
.\" Based on template provided by Tom Christiansen <tchrist@jhereg.perl.com>.
.\"
.TH MUTTER-WINDOW-DEMO 1 "1 June 2004"
.SH NAME
mutter-window-demo \- demo of window features
.SH SYNOPSIS
.B mutter-window-demo
.SH DESCRIPTION
.\" Putting a newline after each sentence can generate better output.
This program demonstrates various kinds of windows that window
managers and window manager themes should handle.
.PP
Be sure to tear off the menu and toolbar, those are also a special
kind of window.
.SH AUTHOR
This manual page was written by Jose M. Moya <josem@die.upm.es>, for
the Debian GNU/Linux system (but may be used by others).
.SH "SEE ALSO"
.\" Always quote multiple words for .SH
.BR x-window-manager (1),
.BR mutter (1),
.BR mutter-theme-viewer (1).

View File

@@ -44,6 +44,7 @@ is
it
ja
ka
kk
kn
ko
ku

View File

@@ -21,9 +21,9 @@ src/core/util.c
src/core/window.c
src/core/window-props.c
src/core/xprops.c
src/mutter.desktop.in
src/mutter-wm.desktop.in
src/mutter-wayland.desktop.in
src/org.gnome.mutter.gschema.xml.in
src/org.gnome.mutter.wayland.gschema.xml.in
src/ui/frames.c
src/ui/menu.c
src/ui/metaaccellabel.c

499
po/as.po

File diff suppressed because it is too large Load Diff

441
po/be.po
View File

@@ -1,10 +1,10 @@
# Ihar Hrachyshka <ihar.hrachyshka@gmail.com>, 2011.
# Ihar Hrachyshka <ihar.hrachyshka@gmail.com>, 2011, 2013.
msgid ""
msgstr ""
"Project-Id-Version: mutter.master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-01 15:50+0000\n"
"POT-Creation-Date: 2013-08-18 20:03+0000\n"
"PO-Revision-Date: 2012-10-13 17:44+0300\n"
"Last-Translator: Ігар Грачышка <ihar.hrachyshka@gmail.com>\n"
"Language-Team: Belarusian <i18n-bel-gnome@googlegroups.com>\n"
@@ -206,7 +206,7 @@ msgstr "Падзяліць прагляд справа"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: ../src/compositor/compositor.c:507
#: ../src/compositor/compositor.c:589
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
@@ -214,11 +214,11 @@ msgid ""
msgstr ""
"Іншы кампазітны кіраўнік вокнаў ужо абслугоўвае экран %i дысплея \"%s\"."
#: ../src/compositor/meta-background.c:1111
#: ../src/compositor/meta-background.c:1076
msgid "background texture could not be created from file"
msgstr "не ўдалося стварыць фонавую тэкстуру з файла"
#: ../src/core/bell.c:320
#: ../src/core/bell.c:322
msgid "Bell event"
msgstr "Падзея з сігналам"
@@ -251,18 +251,18 @@ msgstr "_Пачакаць"
msgid "_Force Quit"
msgstr "_Змусіць да выхаду"
#: ../src/core/display.c:401
#: ../src/core/display.c:421
#, c-format
msgid "Missing %s extension required for compositing"
msgstr ""
"Адсутнічае пашырэнне \"%s\", патрэбнае для ажыццяўлення кампазітнага вываду"
#: ../src/core/display.c:493
#: ../src/core/display.c:513
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "Не ўдалося адкрыць X-дысплей аконнай сістэмы \"%s\"\n"
#: ../src/core/keybindings.c:929
#: ../src/core/keybindings.c:1136
#, c-format
msgid ""
"Some other program is already using the key %s with modifiers %x as a "
@@ -271,41 +271,41 @@ msgstr ""
"Нейкая іншая праграма ўжо выкарыстоўвае як скарот клавішу %s з "
"мадыфікатарамі %x\n"
#: ../src/core/keybindings.c:1129
#: ../src/core/keybindings.c:1333
#, c-format
msgid "\"%s\" is not a valid accelerator\n"
msgstr "\"%s\" - гэта хібны клавіятурны скарот\n"
#: ../src/core/main.c:196
#: ../src/core/main.c:197
msgid "Disable connection to session manager"
msgstr "Выключыць злучэнне з кіраўніком сеансаў"
#: ../src/core/main.c:202
#: ../src/core/main.c:203
msgid "Replace the running window manager"
msgstr "Замяніць дзейнага кіраўніка вокнаў"
#: ../src/core/main.c:208
#: ../src/core/main.c:209
msgid "Specify session management ID"
msgstr "Вызначыць ідэнтыфікатар для кіравання сеансам"
#: ../src/core/main.c:213
#: ../src/core/main.c:214
msgid "X Display to use"
msgstr "Патрэбны X-дысплей"
#: ../src/core/main.c:219
#: ../src/core/main.c:220
msgid "Initialize session from savefile"
msgstr "Ініцыяваць сеанс з файла"
#: ../src/core/main.c:225
#: ../src/core/main.c:226
msgid "Make X calls synchronous"
msgstr "Сінхронна выконваць выклікі X-сістэмы"
#: ../src/core/main.c:494
#: ../src/core/main.c:534
#, c-format
msgid "Failed to scan themes directory: %s\n"
msgstr "Не ўдалося праглядзець каталог з матывамі аздаблення: %s\n"
#: ../src/core/main.c:510
#: ../src/core/main.c:550
#, c-format
msgid ""
"Could not find a theme! Be sure %s exists and contains the usual themes.\n"
@@ -313,6 +313,19 @@ msgstr ""
"Не ўдалося адшукаць матыў аздаблення! Праверце, каб каталог %s існаваў і "
"змяшчаў звычайныя матывы.\n"
#: ../src/core/monitor.c:711
msgid "Built-in display"
msgstr "Убудаваны дысплей"
#. 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"'
#.
#: ../src/core/monitor.c:739
#, c-format
msgid "Unknown %s"
msgstr "Невядомы %s"
#: ../src/core/mutter.c:40
#, c-format
msgid ""
@@ -337,7 +350,7 @@ msgstr "Вывесці нумар версіі праграмы"
msgid "Mutter plugin to use"
msgstr "Патрэбны плугін Mutter"
#: ../src/core/prefs.c:1087
#: ../src/core/prefs.c:1202
msgid ""
"Workarounds for broken applications disabled. Some applications may not "
"behave properly.\n"
@@ -345,12 +358,12 @@ msgstr ""
"Асаблівыя паводзіны для некаторых хібных праграм выключаныя. Некаторыя "
"праграмы могуць перастаць працаваць, як мае быць.\n"
#: ../src/core/prefs.c:1162
#: ../src/core/prefs.c:1277
#, c-format
msgid "Could not parse font description \"%s\" from GSettings key %s\n"
msgstr "Не ўдалося разабраць азначэнне шрыфту \"%s\" з GSettings-ключа %s\n"
#: ../src/core/prefs.c:1228
#: ../src/core/prefs.c:1343
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for mouse button "
@@ -359,7 +372,7 @@ msgstr ""
"Значэнне \"%s\", знойдзенае ў базе канфігурацыйных даных, не азначае "
"мадыфікатар мышынай кнопкі\n"
#: ../src/core/prefs.c:1780
#: ../src/core/prefs.c:1909
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for keybinding "
@@ -368,17 +381,17 @@ msgstr ""
"Значэнне \"%s\", знойдзенае ў базе канфігурацыйных даных, не азначае "
"клавіятурны скарот \"%s\"\n"
#: ../src/core/prefs.c:1879
#: ../src/core/prefs.c:1999
#, c-format
msgid "Workspace %d"
msgstr "Прастора працы %d"
#: ../src/core/screen.c:673
#: ../src/core/screen.c:534
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "Экран %d на дысплеі \"%s\" хібны\n"
#: ../src/core/screen.c:689
#: ../src/core/screen.c:550
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@@ -387,19 +400,19 @@ msgstr ""
"Экран %d на дысплеі \"%s\" ужо мае аконнага кіраўніка. Каб замяніць яго "
"новым, дадайце опцыю --replace.\n"
#: ../src/core/screen.c:716
#: ../src/core/screen.c:577
#, c-format
msgid ""
"Could not acquire window manager selection on screen %d display \"%s\"\n"
msgstr ""
"Не ўдалося пераняць вылучэнне кіраўніка вокнаў для экрана %d дысплея \"%s\"\n"
#: ../src/core/screen.c:794
#: ../src/core/screen.c:655
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr "Экран %d на дысплеі \"%s\" ужо мае кіраўніка вокнаў\n"
#: ../src/core/screen.c:979
#: ../src/core/screen.c:846
#, c-format
msgid "Could not release screen %d on display \"%s\"\n"
msgstr "Не ўдалося вызваліць экран %d на дысплеі \"%s\"\n"
@@ -460,46 +473,45 @@ msgstr ""
"Гэтыя вокны не падтрымліваюць функцыі захавання дзейнага ладу працы, і таму "
"іх прыйдзецца запусціць уручную пасля наступнага ўваходу ў сістэму."
#: ../src/core/util.c:80
#: ../src/core/util.c:84
#, c-format
msgid "Failed to open debug log: %s\n"
msgstr "Не ўдалося адкрыць адладачны журнал: %s\n"
#: ../src/core/util.c:90
#: ../src/core/util.c:94
#, c-format
msgid "Failed to fdopen() log file %s: %s\n"
msgstr "Не ўдалося выканаць fdopen() для журнальнага файла %s: %s\n"
#: ../src/core/util.c:96
#: ../src/core/util.c:100
#, c-format
msgid "Opened log file %s\n"
msgstr "Журнальны файл %s адкрыты\n"
#: ../src/core/util.c:115 ../src/tools/mutter-message.c:149
#, c-format
#: ../src/core/util.c:119
msgid "Mutter was compiled without support for verbose mode\n"
msgstr ""
"Праграма \"Mutter\" была скампіляваная без падтрымкі падрабязнага "
"пратакаліравання\n"
#: ../src/core/util.c:259
#: ../src/core/util.c:264
msgid "Window manager: "
msgstr "Кіраўнік вокнаў: "
#: ../src/core/util.c:407
#: ../src/core/util.c:414
msgid "Bug in window manager: "
msgstr "Хіба ў кіраўніку вокнаў: "
#: ../src/core/util.c:438
#: ../src/core/util.c:445
msgid "Window manager warning: "
msgstr "Перасцярога ад кіраўніка вокнаў: "
#: ../src/core/util.c:466
#: ../src/core/util.c:473
msgid "Window manager error: "
msgstr "Памылка кіраўніка вокнаў: "
#. first time through
#: ../src/core/window.c:7539
#: ../src/core/window.c:7533
#, c-format
msgid ""
"Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER "
@@ -515,7 +527,7 @@ msgstr ""
#. * MWM but not WM_NORMAL_HINTS are basically broken. We complain
#. * about these apps but make them work.
#.
#: ../src/core/window.c:8263
#: ../src/core/window.c:8257
#, c-format
msgid ""
"Window %s sets an MWM hint indicating it isn't resizable, but sets min size "
@@ -525,22 +537,22 @@ msgstr ""
"памеру, але разам з гэтым прызначыла для сябе мінімальны памер %d x %d і "
"максімальны памер %d x %d. Такія паводзіны не маюць сэнсу.\n"
#: ../src/core/window-props.c:318
#: ../src/core/window-props.c:347
#, c-format
msgid "Application set a bogus _NET_WM_PID %lu\n"
msgstr "Праграма прызначыла памылковае значэнне _NET_WM_PID %lu\n"
#: ../src/core/window-props.c:434
#: ../src/core/window-props.c:463
#, c-format
msgid "%s (on %s)"
msgstr "%s (на %s)"
#: ../src/core/window-props.c:1517
#: ../src/core/window-props.c:1546
#, c-format
msgid "Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n"
msgstr "Для %2$s вызначана хібнае акно WM_TRANSIENT_FOR 0x%1$lx.\n"
#: ../src/core/window-props.c:1528
#: ../src/core/window-props.c:1557
#, c-format
msgid "WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n"
msgstr "WM_TRANSIENT_FOR акно 0x%lx для %s стварыла б цыкл.\n"
@@ -689,7 +701,8 @@ msgstr ""
#: ../src/org.gnome.mutter.gschema.xml.in.h:17
msgid "Auto maximize nearly monitor sized windows"
msgstr "Аўтаматычна максімалізаваць вокны, якія расцягнутыя амаль на ўвесь экран"
msgstr ""
"Аўтаматычна максімалізаваць вокны, якія расцягнутыя амаль на ўвесь экран"
#: ../src/org.gnome.mutter.gschema.xml.in.h:18
msgid ""
@@ -707,109 +720,104 @@ msgstr "Выбраць акно з выплыўнога акенца"
msgid "Cancel tab popup"
msgstr "Закрыць выплыўное акенца"
#: ../src/tools/mutter-message.c:123
#, c-format
msgid "Usage: %s\n"
msgstr "Правілы выкарыстання: %s\n"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:69
#: ../src/ui/menu.c:67
msgid "Mi_nimize"
msgstr "_Мінімалізаваць"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:71
#: ../src/ui/menu.c:69
msgid "Ma_ximize"
msgstr "Масімалізаваць"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:73
#: ../src/ui/menu.c:71
msgid "Unma_ximize"
msgstr "Скасаваць масімалізацыю"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:75
#: ../src/ui/menu.c:73
msgid "Roll _Up"
msgstr "_Скруціць акно ў загаловак"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:77
#: ../src/ui/menu.c:75
msgid "_Unroll"
msgstr "Расруціць акно з загалоўка"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:79
#: ../src/ui/menu.c:77
msgid "_Move"
msgstr "_Перамясціць акно"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:81
#: ../src/ui/menu.c:79
msgid "_Resize"
msgstr "_Змяніць памер акна"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:83
#: ../src/ui/menu.c:81
msgid "Move Titlebar On_screen"
msgstr "Перамясціць загаловак акна па _экране"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:86 ../src/ui/menu.c:88
#: ../src/ui/menu.c:84 ../src/ui/menu.c:86
msgid "Always on _Top"
msgstr "Заўсёды _наверсе"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:90
#: ../src/ui/menu.c:88
msgid "_Always on Visible Workspace"
msgstr "Заўсёды на _бачнай прасторы працы"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:92
#: ../src/ui/menu.c:90
msgid "_Only on This Workspace"
msgstr "_Толькі на гэтай прасторы працы"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:94
#: ../src/ui/menu.c:92
msgid "Move to Workspace _Left"
msgstr "Перамясціць на прастору працы з_лева"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:96
#: ../src/ui/menu.c:94
msgid "Move to Workspace R_ight"
msgstr "Перамясціць на прастору працы с_права"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:98
#: ../src/ui/menu.c:96
msgid "Move to Workspace _Up"
msgstr "Перамясціць на прастору працы з_верху"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:100
#: ../src/ui/menu.c:98
msgid "Move to Workspace _Down"
msgstr "Перамясціць на прастору працы з_нізу"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:104
#: ../src/ui/menu.c:102
msgid "_Close"
msgstr "_Закрыць акно"
#: ../src/ui/menu.c:204
#: ../src/ui/menu.c:202
#, c-format
msgid "Workspace %d%n"
msgstr "Прастора працы %d%n"
#: ../src/ui/menu.c:214
#: ../src/ui/menu.c:212
#, c-format
msgid "Workspace 1_0"
msgstr "Прастора працы 1_0"
#: ../src/ui/menu.c:216
#: ../src/ui/menu.c:214
#, c-format
msgid "Workspace %s%d"
msgstr "Прастора працы %s%d"
#: ../src/ui/menu.c:397
#: ../src/ui/menu.c:384
msgid "Move to Another _Workspace"
msgstr "П_ерамясціць на іншую прастору працы"
@@ -911,49 +919,49 @@ msgstr "Mod5"
msgid "%d x %d"
msgstr "%d x %d"
#: ../src/ui/theme.c:235
#: ../src/ui/theme.c:236
msgid "top"
msgstr "верхнюю"
#: ../src/ui/theme.c:237
#: ../src/ui/theme.c:238
msgid "bottom"
msgstr "ніжнюю"
#: ../src/ui/theme.c:239
#: ../src/ui/theme.c:240
msgid "left"
msgstr "левую"
#: ../src/ui/theme.c:241
#: ../src/ui/theme.c:242
msgid "right"
msgstr "правую"
#: ../src/ui/theme.c:269
#: ../src/ui/theme.c:270
#, c-format
msgid "frame geometry does not specify \"%s\" dimension"
msgstr "апісанне геаметрыі рамкі акна не вызначае %s граніцу"
#: ../src/ui/theme.c:288
#: ../src/ui/theme.c:289
#, c-format
msgid "frame geometry does not specify dimension \"%s\" for border \"%s\""
msgstr ""
"апісанне геаметрыі рамкі акна не вызначае %s граніцу для аблямоўкі \"%s\""
#: ../src/ui/theme.c:325
#: ../src/ui/theme.c:326
#, c-format
msgid "Button aspect ratio %g is not reasonable"
msgstr "Прапорцыі кнопкі %g не маюць сэнсу"
#: ../src/ui/theme.c:337
#: ../src/ui/theme.c:338
#, c-format
msgid "Frame geometry does not specify size of buttons"
msgstr "Апісанне геаметрыі рамкі акна не вызначае памер кнопак"
#: ../src/ui/theme.c:1050
#: ../src/ui/theme.c:1051
#, c-format
msgid "Gradients should have at least two colors"
msgstr "Градыент мусіць мець прынамсі два колеры"
#: ../src/ui/theme.c:1202
#: ../src/ui/theme.c:1203
#, c-format
msgid ""
"GTK custom color specification must have color name and fallback in "
@@ -962,7 +970,7 @@ msgstr ""
"Уласная спецыфікацыя колеру GTK мусіць змяшчаць назвы асноўнага і запаснога "
"колераў у дужках, напрыклад, gtk:custom(foo,bar). Не ўдалося разабраць \"%s\""
#: ../src/ui/theme.c:1218
#: ../src/ui/theme.c:1219
#, c-format
msgid ""
"Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-"
@@ -971,7 +979,7 @@ msgstr ""
"Хібны знак \"%c\" у параметры color_name спецыфікацыі gtk:custom, дазволеныя "
"толькі A-Za-z0-9-_"
#: ../src/ui/theme.c:1232
#: ../src/ui/theme.c:1233
#, c-format
msgid ""
"Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not "
@@ -980,7 +988,7 @@ msgstr ""
"Фармат gtk:custom: \"gtk:custom(назваолеруапасны_колер)\"; \"%s\" не "
"адпавядае фармату"
#: ../src/ui/theme.c:1277
#: ../src/ui/theme.c:1278
#, c-format
msgid ""
"GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] "
@@ -989,7 +997,7 @@ msgstr ""
"Спецыфікацыя колеру GTK мусіць мець стан у квадратных дужках, напрыклад, gtk:"
"fg[NORMAL], дзе NORMAL - гэта стан. Не ўдалося разабраць \"%s\""
#: ../src/ui/theme.c:1291
#: ../src/ui/theme.c:1292
#, c-format
msgid ""
"GTK color specification must have a close bracket after the state, e.g. gtk:"
@@ -999,17 +1007,17 @@ msgstr ""
"напрыклад, gtk:fg[NORMAL], дзе NORMAL - гэта стан. Не ўдалося разабраць \"%s"
"\""
#: ../src/ui/theme.c:1302
#: ../src/ui/theme.c:1303
#, c-format
msgid "Did not understand state \"%s\" in color specification"
msgstr "Незразумелы стан \"%s\" у спецыфікацыі колеру"
#: ../src/ui/theme.c:1315
#: ../src/ui/theme.c:1316
#, c-format
msgid "Did not understand color component \"%s\" in color specification"
msgstr "Незразумелы складнік колеру \"%s\" у спецыфікацыі колеру"
#: ../src/ui/theme.c:1344
#: ../src/ui/theme.c:1345
#, c-format
msgid ""
"Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the "
@@ -1018,58 +1026,58 @@ msgstr ""
"Фармат змяшанага колеру - \"blend/bg_color/fg_color/alpha\". \"%s\" не "
"адпавядае фармату."
#: ../src/ui/theme.c:1355
#: ../src/ui/theme.c:1356
#, c-format
msgid "Could not parse alpha value \"%s\" in blended color"
msgstr "Не ўдалося разабраць значэнне альфа \"%s\" ў змяшаным колеры"
#: ../src/ui/theme.c:1365
#: ../src/ui/theme.c:1366
#, c-format
msgid "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
msgstr ""
"Значэнне альфа \"%s\" у змяшаным колеры не ўваходзіць у дыяпазон ад 0.0 да "
"1.0"
#: ../src/ui/theme.c:1412
#: ../src/ui/theme.c:1413
#, c-format
msgid ""
"Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
msgstr ""
"Фармат ценю - \"shade/base_color/factor\". \"%s\" не адпавядае фармату."
#: ../src/ui/theme.c:1423
#: ../src/ui/theme.c:1424
#, c-format
msgid "Could not parse shade factor \"%s\" in shaded color"
msgstr "Не ўдалося разабраць каэфіцыент ценю \"%s\" у зацененым колеры"
#: ../src/ui/theme.c:1433
#: ../src/ui/theme.c:1434
#, c-format
msgid "Shade factor \"%s\" in shaded color is negative"
msgstr "Каэфіцыент ценю \"%s\" у зацененым колеры адмоўны"
#: ../src/ui/theme.c:1462
#: ../src/ui/theme.c:1463
#, c-format
msgid "Could not parse color \"%s\""
msgstr "Не ўдалося разабраць колер \"%s\""
#: ../src/ui/theme.c:1779
#: ../src/ui/theme.c:1780
#, c-format
msgid "Coordinate expression contains character '%s' which is not allowed"
msgstr "Каардынатны выраз змяшчае забаронены знак \"%s\""
#: ../src/ui/theme.c:1806
#: ../src/ui/theme.c:1807
#, c-format
msgid ""
"Coordinate expression contains floating point number '%s' which could not be "
"parsed"
msgstr "Каардынатны выраз змяшчае незразумелы лік з нефіксаванай коскай \"%s\""
#: ../src/ui/theme.c:1820
#: ../src/ui/theme.c:1821
#, c-format
msgid "Coordinate expression contains integer '%s' which could not be parsed"
msgstr "Каардынатны выраз змяшчае незразумелы цэлы лік \"%s\""
#: ../src/ui/theme.c:1941
#: ../src/ui/theme.c:1942
#, c-format
msgid ""
"Coordinate expression contained unknown operator at the start of this text: "
@@ -1077,17 +1085,17 @@ msgid ""
msgstr ""
"Каардынатны выраз змяшчае невядомы аператар у пачатку гэтага тэксту: \"%s\""
#: ../src/ui/theme.c:1998
#: ../src/ui/theme.c:1999
#, c-format
msgid "Coordinate expression was empty or not understood"
msgstr "Каардынатны выраз пусты ці незразумелы"
#: ../src/ui/theme.c:2111 ../src/ui/theme.c:2121 ../src/ui/theme.c:2155
#: ../src/ui/theme.c:2112 ../src/ui/theme.c:2122 ../src/ui/theme.c:2156
#, c-format
msgid "Coordinate expression results in division by zero"
msgstr "Каардынатны выраз вымагае дзялення на нуль"
#: ../src/ui/theme.c:2163
#: ../src/ui/theme.c:2164
#, c-format
msgid ""
"Coordinate expression tries to use mod operator on a floating-point number"
@@ -1095,24 +1103,24 @@ msgstr ""
"Каардынатны выраз спрабуе ўжыць аператар дзялення па модулі для ліку з "
"нефіксаванай коскай"
#: ../src/ui/theme.c:2219
#: ../src/ui/theme.c:2220
#, c-format
msgid ""
"Coordinate expression has an operator \"%s\" where an operand was expected"
msgstr ""
"У каардынатным выразе ўжыты аператар \"%s\" там, дзе мусіў быць аперанд"
#: ../src/ui/theme.c:2228
#: ../src/ui/theme.c:2229
#, c-format
msgid "Coordinate expression had an operand where an operator was expected"
msgstr "У каардынатным выразе ўжыты аперанд там, дзе мусіў быць аператар"
#: ../src/ui/theme.c:2236
#: ../src/ui/theme.c:2237
#, c-format
msgid "Coordinate expression ended with an operator instead of an operand"
msgstr "Каардынатны выраз заканчваецца аператарам, а не аперандам"
#: ../src/ui/theme.c:2246
#: ../src/ui/theme.c:2247
#, c-format
msgid ""
"Coordinate expression has operator \"%c\" following operator \"%c\" with no "
@@ -1121,41 +1129,41 @@ msgstr ""
"У каардынатным выразе за аператарам \"%c\" ідзе аператар \"%c\", але паміж "
"імі няма аперанда"
#: ../src/ui/theme.c:2397 ../src/ui/theme.c:2442
#: ../src/ui/theme.c:2398 ../src/ui/theme.c:2443
#, c-format
msgid "Coordinate expression had unknown variable or constant \"%s\""
msgstr "У каардынатным выразе невядомая зменная альбо канстанта \"%s\""
#: ../src/ui/theme.c:2496
#: ../src/ui/theme.c:2497
#, c-format
msgid "Coordinate expression parser overflowed its buffer."
msgstr "Прылада для разбору каардынатных выразаў перапоўніла свой буфер."
#: ../src/ui/theme.c:2525
#: ../src/ui/theme.c:2526
#, c-format
msgid "Coordinate expression had a close parenthesis with no open parenthesis"
msgstr ""
"У каардынатным выразе ўжытыя дужкі, якія закрываюцца, але няма тых, якія б "
"адкрываліся"
#: ../src/ui/theme.c:2589
#: ../src/ui/theme.c:2590
#, c-format
msgid "Coordinate expression had an open parenthesis with no close parenthesis"
msgstr ""
"У каардынатным выразе ўжытыя дужкі, якія адкрываюцца, але няма тых, якія б "
"закрываліся"
#: ../src/ui/theme.c:2600
#: ../src/ui/theme.c:2601
#, c-format
msgid "Coordinate expression doesn't seem to have any operators or operands"
msgstr "У каардынатным выразе няма ні аператараў, ні аперандаў"
#: ../src/ui/theme.c:2813 ../src/ui/theme.c:2833 ../src/ui/theme.c:2853
#: ../src/ui/theme.c:2814 ../src/ui/theme.c:2834 ../src/ui/theme.c:2854
#, c-format
msgid "Theme contained an expression that resulted in an error: %s\n"
msgstr "Матыў аздаблення змяшчае выраз, які стаў прычынай памылкі: %s\n"
#: ../src/ui/theme.c:4499
#: ../src/ui/theme.c:4500
#, c-format
msgid ""
"<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be "
@@ -1164,25 +1172,25 @@ msgstr ""
"Для гэтага стылю рамкі трэба вызначыць <button function=\"%s\" state=\"%s\" "
"draw_ops=\"whatever\"/>"
#: ../src/ui/theme.c:5010 ../src/ui/theme.c:5035
#: ../src/ui/theme.c:5011 ../src/ui/theme.c:5036
#, c-format
msgid ""
"Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
msgstr ""
"Няма <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"што-небудзь\"/>"
#: ../src/ui/theme.c:5083
#: ../src/ui/theme.c:5082
#, c-format
msgid "Failed to load theme \"%s\": %s\n"
msgstr "Не ўдалося загрузіць матыў аздаблення \"%s\": %s\n"
#: ../src/ui/theme.c:5219 ../src/ui/theme.c:5226 ../src/ui/theme.c:5233
#: ../src/ui/theme.c:5240 ../src/ui/theme.c:5247
#: ../src/ui/theme.c:5218 ../src/ui/theme.c:5225 ../src/ui/theme.c:5232
#: ../src/ui/theme.c:5239 ../src/ui/theme.c:5246
#, c-format
msgid "No <%s> set for theme \"%s\""
msgstr "Для матыву аздаблення \"%2$s\" не прызначана <%1$s>"
#: ../src/ui/theme.c:5255
#: ../src/ui/theme.c:5254
#, c-format
msgid ""
"No frame style set for window type \"%s\" in theme \"%s\", add a <window "
@@ -1191,7 +1199,7 @@ msgstr ""
"Стыль рамкі не вызначаны для вокнаў тыпу \"%s\" для матыву аздаблення \"%s"
"\". Дадайце <window type=\"%s\" style_set=\"штосьці\"/>."
#: ../src/ui/theme.c:5662 ../src/ui/theme.c:5724 ../src/ui/theme.c:5787
#: ../src/ui/theme.c:5661 ../src/ui/theme.c:5723 ../src/ui/theme.c:5786
#, c-format
msgid ""
"User-defined constants must begin with a capital letter; \"%s\" does not"
@@ -1199,7 +1207,7 @@ msgstr ""
"Назвы канстантаў, вызначаных карыстальнікам, мусяць пачынацца з вялікай "
"літары. \"%s\" не адпавядае гэтаму патрабаванню."
#: ../src/ui/theme.c:5670 ../src/ui/theme.c:5732 ../src/ui/theme.c:5795
#: ../src/ui/theme.c:5669 ../src/ui/theme.c:5731 ../src/ui/theme.c:5794
#, c-format
msgid "Constant \"%s\" has already been defined"
msgstr "Канстанта \"%s\" ужо азначана"
@@ -1585,207 +1593,8 @@ msgstr "Выкарыстанне тэксту ўнутры элемента <%s>
msgid "<%s> specified twice for this theme"
msgstr "<%s> двойчы вызначаны для гэтага матыву аздаблення"
#: ../src/ui/theme-parser.c:4334
#: ../src/ui/theme-parser.c:4336
#, c-format
msgid "Failed to find a valid file for theme %s\n"
msgstr "Памылка пошуку правільнага файла для матыву аздаблення %s\n"
#: ../src/ui/theme-viewer.c:99
msgid "_Windows"
msgstr "_Вокны"
#: ../src/ui/theme-viewer.c:100
msgid "_Dialog"
msgstr "_Дыялогавае акенца"
#: ../src/ui/theme-viewer.c:101
msgid "_Modal dialog"
msgstr "_Мадальнае дыялогавае акенца"
#: ../src/ui/theme-viewer.c:102
msgid "_Utility"
msgstr "_Дапаможная праграма"
#: ../src/ui/theme-viewer.c:103
msgid "_Splashscreen"
msgstr "_Экранная застаўка"
#: ../src/ui/theme-viewer.c:104
msgid "_Top dock"
msgstr "_Верхняя ўбудова"
#: ../src/ui/theme-viewer.c:105
msgid "_Bottom dock"
msgstr "_Ніжняя ўбудова"
#: ../src/ui/theme-viewer.c:106
msgid "_Left dock"
msgstr "_Левая ўбудова"
#: ../src/ui/theme-viewer.c:107
msgid "_Right dock"
msgstr "_Правая ўбудова"
#: ../src/ui/theme-viewer.c:108
msgid "_All docks"
msgstr "_Усе ўбудовы"
#: ../src/ui/theme-viewer.c:109
msgid "Des_ktop"
msgstr "_Стол"
#: ../src/ui/theme-viewer.c:115
msgid "Open another one of these windows"
msgstr "Адкрыць чарговае з гэтых вокнаў"
#: ../src/ui/theme-viewer.c:117
msgid "This is a demo button with an 'open' icon"
msgstr "Гэта дэманстрацыйная кнопка са значком \"Адкрыць\""
#: ../src/ui/theme-viewer.c:119
msgid "This is a demo button with a 'quit' icon"
msgstr "Гэта дэманстрацыйная кнопка са значком \"Выйсці\""
#: ../src/ui/theme-viewer.c:248
msgid "This is a sample message in a sample dialog"
msgstr "Гэта ўзорнае паведамленне ва ўзорным дыялогавым акенцы"
#: ../src/ui/theme-viewer.c:328
#, c-format
msgid "Fake menu item %d\n"
msgstr "Несапраўдны пункт меню %d\n"
#: ../src/ui/theme-viewer.c:363
msgid "Border-only window"
msgstr "Акно толькі з аблямоўкай"
#: ../src/ui/theme-viewer.c:365
msgid "Bar"
msgstr "Стужка"
#: ../src/ui/theme-viewer.c:382
msgid "Normal Application Window"
msgstr "Звычайнае акно праграмы"
#: ../src/ui/theme-viewer.c:386
msgid "Dialog Box"
msgstr "Дыялогавае акенца"
#: ../src/ui/theme-viewer.c:390
msgid "Modal Dialog Box"
msgstr "Мадальнае дыялогавае акенца"
#: ../src/ui/theme-viewer.c:394
msgid "Utility Palette"
msgstr "Дапаможная палітра"
#: ../src/ui/theme-viewer.c:398
msgid "Torn-off Menu"
msgstr "Адчэпленае меню"
#: ../src/ui/theme-viewer.c:402
msgid "Border"
msgstr "Аблямоўка"
#: ../src/ui/theme-viewer.c:406
msgid "Attached Modal Dialog"
msgstr "Прычапленае мадальнае дыялогавае акенца"
#: ../src/ui/theme-viewer.c:737
#, c-format
msgid "Button layout test %d"
msgstr "Выпрабаванне размяшчэння кнопак %d"
#: ../src/ui/theme-viewer.c:766
#, c-format
msgid "%g milliseconds to draw one window frame"
msgstr "%g мілісекунд, каб намаляваць адну рамку акна"
#: ../src/ui/theme-viewer.c:811
#, c-format
msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
msgstr "Правілы карыстання: metacity-theme-viewer [НАЗВА_МАТЫВУ]\n"
#: ../src/ui/theme-viewer.c:818
#, c-format
msgid "Error loading theme: %s\n"
msgstr "Памылка загрузкі матыву аздаблення: %s\n"
#: ../src/ui/theme-viewer.c:824
#, c-format
msgid "Loaded theme \"%s\" in %g seconds\n"
msgstr "Матыў аздаблення \"%s\" загружаны за %g секунд\n"
#: ../src/ui/theme-viewer.c:869
msgid "Normal Title Font"
msgstr "Звычайны шрыфт загалоўка"
#: ../src/ui/theme-viewer.c:875
msgid "Small Title Font"
msgstr "Маленькі шрыфт загалоўка"
#: ../src/ui/theme-viewer.c:881
msgid "Large Title Font"
msgstr "Вялікі шрыфт загалоўка"
#: ../src/ui/theme-viewer.c:886
msgid "Button Layouts"
msgstr "Размяшчэнне кнопак"
#: ../src/ui/theme-viewer.c:891
msgid "Benchmark"
msgstr "Выпрабаванне"
#: ../src/ui/theme-viewer.c:947
msgid "Window Title Goes Here"
msgstr "Месца для загалоўка акна"
#: ../src/ui/theme-viewer.c:1053
#, c-format
msgid ""
"Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g "
"seconds wall clock time including X server resources (%g milliseconds per "
"frame)\n"
msgstr ""
"Намалявана %d рамак цягам %g секунд кліенцкага часу (%g мілісекунд на рамку) "
"і %g секунд каляндарнага часу, уключна з рэсурсамі X-сервера (%g мілісекунд "
"на рамку)\n"
#: ../src/ui/theme-viewer.c:1273
msgid "position expression test returned TRUE but set error"
msgstr "выпрабаванне выразу пазіцыі вярнула TRUE, але паведаміла аб памылцы"
#: ../src/ui/theme-viewer.c:1275
msgid "position expression test returned FALSE but didn't set error"
msgstr ""
"выпрабаванне выразу пазіцыі вярнула FALSE, але не паведаміла аб памылцы"
#: ../src/ui/theme-viewer.c:1279
msgid "Error was expected but none given"
msgstr "Чакалася памылка, але звесткі не атрыманыя"
#: ../src/ui/theme-viewer.c:1281
#, c-format
msgid "Error %d was expected but %d given"
msgstr "Чакалася памылка %d, але атрымана %d"
#: ../src/ui/theme-viewer.c:1287
#, c-format
msgid "Error not expected but one was returned: %s"
msgstr "Атрымана нечаканая памылка: %s"
#: ../src/ui/theme-viewer.c:1291
#, c-format
msgid "x value was %d, %d was expected"
msgstr "X-значэнне было %d, а чакалася %d"
#: ../src/ui/theme-viewer.c:1294
#, c-format
msgid "y value was %d, %d was expected"
msgstr "Y-значэнне было %d, а чакалася %d"
#: ../src/ui/theme-viewer.c:1359
#, c-format
msgid "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
msgstr ""
"%d каардынатных выразаў разабраныя за %g секунд (у сярэднім %g секунд)\n"

610
po/de.po

File diff suppressed because it is too large Load Diff

231
po/et.po
View File

@@ -14,8 +14,8 @@ msgstr ""
"Project-Id-Version: mutter MASTER\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-12 18:53+0000\n"
"PO-Revision-Date: 2013-03-12 20:55+0300\n"
"POT-Creation-Date: 2013-09-10 15:25+0000\n"
"PO-Revision-Date: 2013-09-11 23:20+0300\n"
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
"Language-Team: Estonian <>\n"
"Language: et\n"
@@ -23,6 +23,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
"X-Generator: Poedit 1.5.4\n"
msgid "Navigation"
msgstr "Navigeerimine"
@@ -249,6 +250,17 @@ msgid ""
msgstr ""
"Teemat ei leitud! Veendu, et %s on olemas ja sisaldab harilikke teemasid.\n"
msgid "Built-in display"
msgstr "Sisseehitatud kuva"
#. 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"'
#.
#, c-format
msgid "Unknown %s"
msgstr "Tundmatu %s"
#, c-format
msgid ""
"mutter %s\n"
@@ -381,7 +393,6 @@ msgstr "Tõrge logifaili %s avamisel funktsiooniga fdopen(): %s\n"
msgid "Opened log file %s\n"
msgstr "Avati logifail %s\n"
#, c-format
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Mutter kompileeriti ilma jutuka režiimi toeta\n"
@@ -572,10 +583,6 @@ msgstr "Akna valimine tabulaatori hüpikaknalt"
msgid "Cancel tab popup"
msgstr "Tabulaatori hüpikakna katkestamine"
#, c-format
msgid "Usage: %s\n"
msgstr "Kasutamine: %s\n"
#. Translators: Translate this string the same way as you do in libwnck!
msgid "Mi_nimize"
msgstr "_Minimeeri"
@@ -1281,159 +1288,151 @@ msgstr "Selle teema jaoks on <%s> määratud kaks korda"
msgid "Failed to find a valid file for theme %s\n"
msgstr "Tõrge %s teema jaoks korrektse faili leidmisel\n"
msgid "_Windows"
msgstr "_Aknad"
#~ msgid "Usage: %s\n"
#~ msgstr "Kasutamine: %s\n"
msgid "_Dialog"
msgstr "_Dialoog"
#~ msgid "_Windows"
#~ msgstr "_Aknad"
msgid "_Modal dialog"
msgstr "_Modaaldialoog"
#~ msgid "_Dialog"
#~ msgstr "_Dialoog"
msgid "_Utility"
msgstr "_Utiliit"
#~ msgid "_Modal dialog"
#~ msgstr "_Modaaldialoog"
msgid "_Splashscreen"
msgstr "_Käivitusekraan"
#~ msgid "_Utility"
#~ msgstr "_Utiliit"
msgid "_Top dock"
msgstr "Ü_lemine dokk"
#~ msgid "_Splashscreen"
#~ msgstr "_Käivitusekraan"
msgid "_Bottom dock"
msgstr "_Alumine dokk"
#~ msgid "_Top dock"
#~ msgstr "Ü_lemine dokk"
msgid "_Left dock"
msgstr "_Vasak dokk"
#~ msgid "_Bottom dock"
#~ msgstr "_Alumine dokk"
msgid "_Right dock"
msgstr "_Parem dokk"
#~ msgid "_Left dock"
#~ msgstr "_Vasak dokk"
msgid "_All docks"
msgstr "_Kõik dokid"
#~ msgid "_Right dock"
#~ msgstr "_Parem dokk"
msgid "Des_ktop"
msgstr "_Töölaud"
#~ msgid "_All docks"
#~ msgstr "_Kõik dokid"
msgid "Open another one of these windows"
msgstr "Ava neist akendest järgmine"
#~ msgid "Des_ktop"
#~ msgstr "_Töölaud"
msgid "This is a demo button with an 'open' icon"
msgstr "See on näidisnupp koos 'ava' ikooniga"
#~ msgid "Open another one of these windows"
#~ msgstr "Ava neist akendest järgmine"
msgid "This is a demo button with a 'quit' icon"
msgstr "See on näidisnupp koos 'lõpeta' ikooniga"
#~ msgid "This is a demo button with an 'open' icon"
#~ msgstr "See on näidisnupp koos 'ava' ikooniga"
msgid "This is a sample message in a sample dialog"
msgstr "See on näidisteade näidisdialoogis"
#~ msgid "This is a demo button with a 'quit' icon"
#~ msgstr "See on näidisnupp koos 'lõpeta' ikooniga"
#, c-format
msgid "Fake menu item %d\n"
msgstr "Võltsitud menüüpunkt %d\n"
#~ msgid "This is a sample message in a sample dialog"
#~ msgstr "See on näidisteade näidisdialoogis"
msgid "Border-only window"
msgstr "Ainult raamiga aken"
#~ msgid "Fake menu item %d\n"
#~ msgstr "Võltsitud menüüpunkt %d\n"
msgid "Bar"
msgstr "Riba"
#~ msgid "Border-only window"
#~ msgstr "Ainult raamiga aken"
msgid "Normal Application Window"
msgstr "Tavaline rakenduseaken"
#~ msgid "Bar"
#~ msgstr "Riba"
msgid "Dialog Box"
msgstr "Dialoogikast"
#~ msgid "Normal Application Window"
#~ msgstr "Tavaline rakenduseaken"
msgid "Modal Dialog Box"
msgstr "Modaalne dialoogikast"
#~ msgid "Dialog Box"
#~ msgstr "Dialoogikast"
msgid "Utility Palette"
msgstr "Rakendite palett"
#~ msgid "Modal Dialog Box"
#~ msgstr "Modaalne dialoogikast"
msgid "Torn-off Menu"
msgstr "Ärarebitav menüü"
#~ msgid "Utility Palette"
#~ msgstr "Rakendite palett"
msgid "Border"
msgstr "Raam"
#~ msgid "Torn-off Menu"
#~ msgstr "Ärarebitav menüü"
msgid "Attached Modal Dialog"
msgstr "Kinnistatud modaaldialoog"
#~ msgid "Border"
#~ msgstr "Raam"
#, c-format
msgid "Button layout test %d"
msgstr "Nuppude paigutuse test %d"
#~ msgid "Attached Modal Dialog"
#~ msgstr "Kinnistatud modaaldialoog"
#, c-format
msgid "%g milliseconds to draw one window frame"
msgstr "%g millisekundit kulub ühe akna raami joonistamiseks"
#~ msgid "Button layout test %d"
#~ msgstr "Nuppude paigutuse test %d"
#, c-format
msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
msgstr "Kasutamine: metacity-theme-viewer [TEEMANIMI]\n"
#~ msgid "%g milliseconds to draw one window frame"
#~ msgstr "%g millisekundit kulub ühe akna raami joonistamiseks"
#, c-format
msgid "Error loading theme: %s\n"
msgstr "Viga teema laadimisel: %s\n"
#~ msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
#~ msgstr "Kasutamine: metacity-theme-viewer [TEEMANIMI]\n"
#, c-format
msgid "Loaded theme \"%s\" in %g seconds\n"
msgstr "Teema \"%s\" laaditi %g sekundiga\n"
#~ msgid "Error loading theme: %s\n"
#~ msgstr "Viga teema laadimisel: %s\n"
msgid "Normal Title Font"
msgstr "Tiitli tavasuurusega kirjatüüp"
#~ msgid "Loaded theme \"%s\" in %g seconds\n"
#~ msgstr "Teema \"%s\" laaditi %g sekundiga\n"
msgid "Small Title Font"
msgstr "Tiitli väike kirjatüüp"
#~ msgid "Normal Title Font"
#~ msgstr "Tiitli tavasuurusega kirjatüüp"
msgid "Large Title Font"
msgstr "Tiitli suur kirjatüüp"
#~ msgid "Small Title Font"
#~ msgstr "Tiitli väike kirjatüüp"
msgid "Button Layouts"
msgstr "Nuppude paigutus"
#~ msgid "Large Title Font"
#~ msgstr "Tiitli suur kirjatüüp"
msgid "Benchmark"
msgstr "Jõudlus"
#~ msgid "Button Layouts"
#~ msgstr "Nuppude paigutus"
msgid "Window Title Goes Here"
msgstr "Siia tuleb akna pealkiri"
#~ msgid "Benchmark"
#~ msgstr "Jõudlus"
#, c-format
msgid ""
"Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g "
"seconds wall clock time including X server resources (%g milliseconds per "
"frame)\n"
msgstr ""
"Joonistati %d kaadrit %g kliendi-kella sekundiga (%g millisekundit kaadrile) "
"ja %g sekundiga seinakella järgi, millesse on kaasatud X-serveri "
"ressursikasutus (%g millisekundit kaadrile)\n"
#~ msgid "Window Title Goes Here"
#~ msgstr "Siia tuleb akna pealkiri"
msgid "position expression test returned TRUE but set error"
msgstr "asukoha avaldise kontroll tagastas TÕENE, aga määras vea"
#~ msgid ""
#~ "Drew %d frames in %g client-side seconds (%g milliseconds per frame) and "
#~ "%g seconds wall clock time including X server resources (%g milliseconds "
#~ "per frame)\n"
#~ msgstr ""
#~ "Joonistati %d kaadrit %g kliendi-kella sekundiga (%g millisekundit "
#~ "kaadrile) ja %g sekundiga seinakella järgi, millesse on kaasatud X-"
#~ "serveri ressursikasutus (%g millisekundit kaadrile)\n"
msgid "position expression test returned FALSE but didn't set error"
msgstr "asukoha avaldise kontroll tagastas VÄÄR, aga ei määranud viga"
#~ msgid "position expression test returned TRUE but set error"
#~ msgstr "asukoha avaldise kontroll tagastas TÕENE, aga määras vea"
msgid "Error was expected but none given"
msgstr "Oodati viga, aga ühtegi ei edastatud"
#~ msgid "position expression test returned FALSE but didn't set error"
#~ msgstr "asukoha avaldise kontroll tagastas VÄÄR, aga ei määranud viga"
#, c-format
msgid "Error %d was expected but %d given"
msgstr "Oodati viga %d, aga edastati viga %d"
#~ msgid "Error was expected but none given"
#~ msgstr "Oodati viga, aga ühtegi ei edastatud"
#, c-format
msgid "Error not expected but one was returned: %s"
msgstr "Viga ei oodatud, aga üks edastati: %s"
#~ msgid "Error %d was expected but %d given"
#~ msgstr "Oodati viga %d, aga edastati viga %d"
#, c-format
msgid "x value was %d, %d was expected"
msgstr "x väärtus oli %d, oodati väärtust %d"
#~ msgid "Error not expected but one was returned: %s"
#~ msgstr "Viga ei oodatud, aga üks edastati: %s"
#, c-format
msgid "y value was %d, %d was expected"
msgstr "y väärtus oli %d, oodati väärtust %d"
#~ msgid "x value was %d, %d was expected"
#~ msgstr "x väärtus oli %d, oodati väärtust %d"
#, c-format
msgid "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
msgstr ""
"%d koordinaatide avaldis töödeldi %g sekundiga (keskmine %g sekundit)\n"
#~ msgid "y value was %d, %d was expected"
#~ msgstr "y väärtus oli %d, oodati väärtust %d"
#~ msgid ""
#~ "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
#~ msgstr ""
#~ "%d koordinaatide avaldis töödeldi %g sekundiga (keskmine %g sekundit)\n"
#~ msgid "Minimize window"
#~ msgstr "Akna minimeerimine"

512
po/fi.po

File diff suppressed because it is too large Load Diff

327
po/id.po
View File

@@ -11,15 +11,15 @@ msgstr ""
"Project-Id-Version: mutter master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-28 10:28+0000\n"
"PO-Revision-Date: 2013-03-30 11:24+0700\n"
"POT-Creation-Date: 2013-08-18 20:03+0000\n"
"PO-Revision-Date: 2013-09-14 15:44+0700\n"
"Last-Translator: Andika Triwidada <andika@gmail.com>\n"
"Language-Team: Indonesian <gnome@i15n.org>\n"
"Language: id\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.5\n"
"X-Generator: Poedit 1.5.7\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: ../src/50-mutter-navigation.xml.in.h:1
@@ -212,7 +212,7 @@ msgstr "Tampilan dipisah ke kanan"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: ../src/compositor/compositor.c:568
#: ../src/compositor/compositor.c:589
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
@@ -220,7 +220,7 @@ msgid ""
msgstr ""
"Manajer komposit lain telah berjalan pada layar %i pada tampilan \"%s\"."
#: ../src/compositor/meta-background.c:1065
#: ../src/compositor/meta-background.c:1076
msgid "background texture could not be created from file"
msgstr "tekstur latar tak bisa dibuat dari berkas"
@@ -257,24 +257,24 @@ msgstr "_Tunggu"
msgid "_Force Quit"
msgstr "_Matikan Paksa"
#: ../src/core/display.c:401
#: ../src/core/display.c:421
#, c-format
msgid "Missing %s extension required for compositing"
msgstr "Kehilangan ekstensi %s yang diperlukan untuk pengkomposisian"
#: ../src/core/display.c:493
#: ../src/core/display.c:513
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "Gagal membuka tampilan X Window System '%s'\n"
#: ../src/core/keybindings.c:935
#: ../src/core/keybindings.c:1136
#, c-format
msgid ""
"Some other program is already using the key %s with modifiers %x as a "
"binding\n"
msgstr "Ada program lain yang menggunakan tombol %s dengan kombinasi %x\n"
#: ../src/core/keybindings.c:1135
#: ../src/core/keybindings.c:1333
#, c-format
msgid "\"%s\" is not a valid accelerator\n"
msgstr "\"%s\" bukan akselerator yang valid\n"
@@ -314,6 +314,19 @@ msgid ""
"Could not find a theme! Be sure %s exists and contains the usual themes.\n"
msgstr "Tak menemukan tema! Pastikan %s ada dan berisi tema yang biasa.\n"
#: ../src/core/monitor.c:711
msgid "Built-in display"
msgstr "Tampilan bawaan"
#. 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"'
#.
#: ../src/core/monitor.c:739
#, c-format
msgid "Unknown %s"
msgstr "%s tidak dikenal"
#: ../src/core/mutter.c:40
#, c-format
msgid ""
@@ -338,7 +351,7 @@ msgstr "Cetak versi"
msgid "Mutter plugin to use"
msgstr "Pengaya Mutter yang dipakai"
#: ../src/core/prefs.c:1095
#: ../src/core/prefs.c:1202
msgid ""
"Workarounds for broken applications disabled. Some applications may not "
"behave properly.\n"
@@ -346,12 +359,12 @@ msgstr ""
"Pencegahan kesalahan bagi aplikasi yang rusak sedang dinonaktifkan. Mungkin "
"nanti ada beberapa aplikasi yang akan bertingkah aneh.\n"
#: ../src/core/prefs.c:1170
#: ../src/core/prefs.c:1277
#, c-format
msgid "Could not parse font description \"%s\" from GSettings key %s\n"
msgstr "Tak dapat mengurai deskripsi fonta \"%s\" dari kunci GSettings %s\n"
#: ../src/core/prefs.c:1236
#: ../src/core/prefs.c:1343
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for mouse button "
@@ -360,7 +373,7 @@ msgstr ""
"\"%s\" yang ada pada database konfigurasi bukanlah nilai yang benar untuk "
"tombol mouse.\n"
#: ../src/core/prefs.c:1788
#: ../src/core/prefs.c:1909
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for keybinding "
@@ -369,17 +382,17 @@ msgstr ""
"\"%s\" yang ada pada database konfigurasi bernilai tidak benar untuk "
"kombinasi tombol \"%s\"\n"
#: ../src/core/prefs.c:1887
#: ../src/core/prefs.c:1999
#, c-format
msgid "Workspace %d"
msgstr "Area kerja %d"
#: ../src/core/screen.c:691
#: ../src/core/screen.c:534
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "Layar %d pada tampilan '%s' tidak benar\n"
#: ../src/core/screen.c:707
#: ../src/core/screen.c:550
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@@ -388,7 +401,7 @@ msgstr ""
"Layar %d pada tampilan \"%s\" sudah memiliki pengatur jendela. Cobalah "
"gunakan pilihan --replace untuk mengganti pengatur jendela yang aktif.\n"
#: ../src/core/screen.c:734
#: ../src/core/screen.c:577
#, c-format
msgid ""
"Could not acquire window manager selection on screen %d display \"%s\"\n"
@@ -396,12 +409,12 @@ msgstr ""
"Tidak dapat mendapatkan pilihan pengatur jendela pada layar %d tampilan \"%s"
"\"\n"
#: ../src/core/screen.c:812
#: ../src/core/screen.c:655
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr "Layar %d pada tampilan \"%s\" sudah ada pengatur jendelanya\n"
#: ../src/core/screen.c:998
#: ../src/core/screen.c:846
#, c-format
msgid "Could not release screen %d on display \"%s\"\n"
msgstr "Layar %d pada tampilan \"%s\" tidak dapat dilepas\n"
@@ -476,8 +489,7 @@ msgstr "Gagal melakukan fdopen pada berkas log %s: %s\n"
msgid "Opened log file %s\n"
msgstr "Berkas log yang dibuka %s\n"
#: ../src/core/util.c:119 ../src/tools/mutter-message.c:149
#, c-format
#: ../src/core/util.c:119
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Muter dikompilasi tanpa dukungan mode riuh\n"
@@ -485,20 +497,20 @@ msgstr "Muter dikompilasi tanpa dukungan mode riuh\n"
msgid "Window manager: "
msgstr "Pengatur jendela: "
#: ../src/core/util.c:412
#: ../src/core/util.c:414
msgid "Bug in window manager: "
msgstr "Bug pada pengatur jendela: "
#: ../src/core/util.c:443
#: ../src/core/util.c:445
msgid "Window manager warning: "
msgstr "Peringatan pengatur jendela: "
#: ../src/core/util.c:471
#: ../src/core/util.c:473
msgid "Window manager error: "
msgstr "Eror pengatur jendela: "
#. first time through
#: ../src/core/window.c:7596
#: ../src/core/window.c:7533
#, c-format
msgid ""
"Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER "
@@ -514,7 +526,7 @@ msgstr ""
#. * MWM but not WM_NORMAL_HINTS are basically broken. We complain
#. * about these apps but make them work.
#.
#: ../src/core/window.c:8320
#: ../src/core/window.c:8257
#, c-format
msgid ""
"Window %s sets an MWM hint indicating it isn't resizable, but sets min size "
@@ -524,22 +536,22 @@ msgstr ""
"ukurannya, sedangkan ukuran minimalnya adalah %d x %d dan maksimal %d x %d "
"yang tidak masuk di akal.\n"
#: ../src/core/window-props.c:318
#: ../src/core/window-props.c:347
#, c-format
msgid "Application set a bogus _NET_WM_PID %lu\n"
msgstr "Aplikasi telah membuat _NET_WM_PID %lu bohongan\n"
#: ../src/core/window-props.c:434
#: ../src/core/window-props.c:463
#, c-format
msgid "%s (on %s)"
msgstr "%s (pada %s)"
#: ../src/core/window-props.c:1517
#: ../src/core/window-props.c:1546
#, c-format
msgid "Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n"
msgstr "WM_TRANSIENT_FOR salah jendela 0x%lx ditentukan untuk %s.\n"
#: ../src/core/window-props.c:1528
#: ../src/core/window-props.c:1557
#, c-format
msgid "WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n"
msgstr "Jendela WM_TRANSIENT_FOR 0x%lx untuk %s akan membuat loop.\n"
@@ -703,109 +715,104 @@ msgstr "Pilih jendela dari popup tab"
msgid "Cancel tab popup"
msgstr "Batalkan popup tab"
#: ../src/tools/mutter-message.c:123
#, c-format
msgid "Usage: %s\n"
msgstr "Cara pakai: %s\n"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:69
#: ../src/ui/menu.c:67
msgid "Mi_nimize"
msgstr "Kecilka_n"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:71
#: ../src/ui/menu.c:69
msgid "Ma_ximize"
msgstr "Pe_rbesar"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:73
#: ../src/ui/menu.c:71
msgid "Unma_ximize"
msgstr "Kem_balikan"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:75
#: ../src/ui/menu.c:73
msgid "Roll _Up"
msgstr "G_ulung"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:77
#: ../src/ui/menu.c:75
msgid "_Unroll"
msgstr "B_uka"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:79
#: ../src/ui/menu.c:77
msgid "_Move"
msgstr "_Pindahkan"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:81
#: ../src/ui/menu.c:79
msgid "_Resize"
msgstr "Ganti·Uku_ran"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:83
#: ../src/ui/menu.c:81
msgid "Move Titlebar On_screen"
msgstr "Pindahkan Judul Pada _layar"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:86 ../src/ui/menu.c:88
#: ../src/ui/menu.c:84 ../src/ui/menu.c:86
msgid "Always on _Top"
msgstr "Selalu di A_tas"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:90
#: ../src/ui/menu.c:88
msgid "_Always on Visible Workspace"
msgstr "T_ampak pada Area Kerja Aktif"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:92
#: ../src/ui/menu.c:90
msgid "_Only on This Workspace"
msgstr "_Tampak pada Area Kerja Ini Saja"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:94
#: ../src/ui/menu.c:92
msgid "Move to Workspace _Left"
msgstr "Pindahkan ke Area Kerja _Kiri"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:96
#: ../src/ui/menu.c:94
msgid "Move to Workspace R_ight"
msgstr "Pindahkan ke A_rea Kerja Kanan"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:98
#: ../src/ui/menu.c:96
msgid "Move to Workspace _Up"
msgstr "Pindahkan ke Area Kerja Ata_s"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:100
#: ../src/ui/menu.c:98
msgid "Move to Workspace _Down"
msgstr "Pindahkan ke Area Kerja _Bawah"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:104
#: ../src/ui/menu.c:102
msgid "_Close"
msgstr "_Tutup"
#: ../src/ui/menu.c:204
#: ../src/ui/menu.c:202
#, c-format
msgid "Workspace %d%n"
msgstr "Area Kerja %d%n"
#: ../src/ui/menu.c:214
#: ../src/ui/menu.c:212
#, c-format
msgid "Workspace 1_0"
msgstr "Area Kerja 1_0"
#: ../src/ui/menu.c:216
#: ../src/ui/menu.c:214
#, c-format
msgid "Workspace %s%d"
msgstr "Area Kerja %s%d"
#: ../src/ui/menu.c:397
#: ../src/ui/menu.c:384
msgid "Move to Another _Workspace"
msgstr "Pindahkan ke Area Kerja _Lain"
@@ -1163,18 +1170,18 @@ msgid ""
msgstr ""
"<frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/> tidak ada"
#: ../src/ui/theme.c:5084
#: ../src/ui/theme.c:5082
#, c-format
msgid "Failed to load theme \"%s\": %s\n"
msgstr "Gagal membuka tema \"%s\": %s\n"
#: ../src/ui/theme.c:5220 ../src/ui/theme.c:5227 ../src/ui/theme.c:5234
#: ../src/ui/theme.c:5241 ../src/ui/theme.c:5248
#: ../src/ui/theme.c:5218 ../src/ui/theme.c:5225 ../src/ui/theme.c:5232
#: ../src/ui/theme.c:5239 ../src/ui/theme.c:5246
#, c-format
msgid "No <%s> set for theme \"%s\""
msgstr "Tidak ada <%s> yang ditentukan untuk tema \"%s\""
#: ../src/ui/theme.c:5256
#: ../src/ui/theme.c:5254
#, c-format
msgid ""
"No frame style set for window type \"%s\" in theme \"%s\", add a <window "
@@ -1183,14 +1190,14 @@ msgstr ""
"Tidak ada gaya frame untuk tipe window \"%s\" pada tema \"%s\". Tambah dulu "
"elemen <window type=\"%s\" style_set=\"whatever\"/>"
#: ../src/ui/theme.c:5663 ../src/ui/theme.c:5725 ../src/ui/theme.c:5788
#: ../src/ui/theme.c:5661 ../src/ui/theme.c:5723 ../src/ui/theme.c:5786
#, c-format
msgid ""
"User-defined constants must begin with a capital letter; \"%s\" does not"
msgstr ""
"Konstanta buatan pengguna harus dimulai dengan huruf besar: \"%s\" tidak"
#: ../src/ui/theme.c:5671 ../src/ui/theme.c:5733 ../src/ui/theme.c:5796
#: ../src/ui/theme.c:5669 ../src/ui/theme.c:5731 ../src/ui/theme.c:5794
#, c-format
msgid "Constant \"%s\" has already been defined"
msgstr "Konstanta \"%s\" telah didefinisikan sebelumnya"
@@ -1578,201 +1585,3 @@ msgstr "<%s> disebutkan dua kali pada tema ini"
#, c-format
msgid "Failed to find a valid file for theme %s\n"
msgstr "Gagal menemukan berkas yang sah untuk tema %s\n"
#: ../src/ui/theme-viewer.c:99
msgid "_Windows"
msgstr "_Jendela"
#: ../src/ui/theme-viewer.c:100
msgid "_Dialog"
msgstr "_Dialog"
#: ../src/ui/theme-viewer.c:101
msgid "_Modal dialog"
msgstr "Dialog _modal"
#: ../src/ui/theme-viewer.c:102
msgid "_Utility"
msgstr "_Utilitas"
#: ../src/ui/theme-viewer.c:103
msgid "_Splashscreen"
msgstr "Layar _pembuka"
#: ../src/ui/theme-viewer.c:104
msgid "_Top dock"
msgstr "Dok a_tas"
#: ../src/ui/theme-viewer.c:105
msgid "_Bottom dock"
msgstr "Dok _bawah"
#: ../src/ui/theme-viewer.c:106
msgid "_Left dock"
msgstr "Dok k_iri"
#: ../src/ui/theme-viewer.c:107
msgid "_Right dock"
msgstr "Dok kana_n"
#: ../src/ui/theme-viewer.c:108
msgid "_All docks"
msgstr "Semu_a dok"
#: ../src/ui/theme-viewer.c:109
msgid "Des_ktop"
msgstr "Des_ktop"
#: ../src/ui/theme-viewer.c:115
msgid "Open another one of these windows"
msgstr "Buka lagi jendela semacam ini"
#: ../src/ui/theme-viewer.c:117
msgid "This is a demo button with an 'open' icon"
msgstr "Ini contoh tombol dengan ikon 'open'"
#: ../src/ui/theme-viewer.c:119
msgid "This is a demo button with a 'quit' icon"
msgstr "Ini contoh tombol dengan ikon 'quit'"
#: ../src/ui/theme-viewer.c:248
msgid "This is a sample message in a sample dialog"
msgstr "Ini contoh pesan pada suatu dialog"
#: ../src/ui/theme-viewer.c:328
#, c-format
msgid "Fake menu item %d\n"
msgstr "Item menu %d\n"
#: ../src/ui/theme-viewer.c:363
msgid "Border-only window"
msgstr "Jendela dengan garis pembatas"
#: ../src/ui/theme-viewer.c:365
msgid "Bar"
msgstr "Kotak"
#: ../src/ui/theme-viewer.c:382
msgid "Normal Application Window"
msgstr "Jendela Aplikasi Normal"
#: ../src/ui/theme-viewer.c:386
msgid "Dialog Box"
msgstr "Kotak Dialog"
#: ../src/ui/theme-viewer.c:390
msgid "Modal Dialog Box"
msgstr "Kotak Dialog Modal"
#: ../src/ui/theme-viewer.c:394
msgid "Utility Palette"
msgstr "Kotak Perkakas"
#: ../src/ui/theme-viewer.c:398
msgid "Torn-off Menu"
msgstr "Menu Dapat Dilepas"
#: ../src/ui/theme-viewer.c:402
msgid "Border"
msgstr "Batas"
#: ../src/ui/theme-viewer.c:406
msgid "Attached Modal Dialog"
msgstr "Dialog Modal yang Dilampirkan"
#: ../src/ui/theme-viewer.c:737
#, c-format
msgid "Button layout test %d"
msgstr "Tes komposisi tombol %d"
#: ../src/ui/theme-viewer.c:766
#, c-format
msgid "%g milliseconds to draw one window frame"
msgstr "lama waktu menggambar satu bingkai jendela %g milidetik"
#: ../src/ui/theme-viewer.c:811
#, c-format
msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
msgstr "Cara pakai: metacity-theme-viewer [NAMA TEMA]\n"
#: ../src/ui/theme-viewer.c:818
#, c-format
msgid "Error loading theme: %s\n"
msgstr "Ada error saat membaca tema: %s\n"
#: ../src/ui/theme-viewer.c:824
#, c-format
msgid "Loaded theme \"%s\" in %g seconds\n"
msgstr "Tema \"%s\" dibuka dalam %g detik\n"
#: ../src/ui/theme-viewer.c:869
msgid "Normal Title Font"
msgstr "Judul dengan huruf normal"
#: ../src/ui/theme-viewer.c:875
msgid "Small Title Font"
msgstr "Judul dengan huruf ukuran kecil"
#: ../src/ui/theme-viewer.c:881
msgid "Large Title Font"
msgstr "Judul Raksasa"
#: ../src/ui/theme-viewer.c:886
msgid "Button Layouts"
msgstr "Komposisi Tombol"
#: ../src/ui/theme-viewer.c:891
msgid "Benchmark"
msgstr "Pengukuran"
#: ../src/ui/theme-viewer.c:947
msgid "Window Title Goes Here"
msgstr "Ini tempat judul jendela"
#: ../src/ui/theme-viewer.c:1053
#, c-format
msgid ""
"Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g "
"seconds wall clock time including X server resources (%g milliseconds per "
"frame)\n"
msgstr ""
"%d frame dibuat dalam %g detik dalam waktu klien (%g milidetik per frame) "
"dan %g detik dalam waktu sebenarnya (%g milidetik per frame)\n"
#: ../src/ui/theme-viewer.c:1273
msgid "position expression test returned TRUE but set error"
msgstr "tes ekspresi posisi berakhir TRUE tapi justru ada error"
#: ../src/ui/theme-viewer.c:1275
msgid "position expression test returned FALSE but didn't set error"
msgstr "tes ekspresi posisi berakhir FALSE tapi tidak ada error"
#: ../src/ui/theme-viewer.c:1279
msgid "Error was expected but none given"
msgstr "Seharusnya ada error, tapi ini kok tidak ada"
#: ../src/ui/theme-viewer.c:1281
#, c-format
msgid "Error %d was expected but %d given"
msgstr "Seharunya ada error %d, tapi yang terjadi %d"
#: ../src/ui/theme-viewer.c:1287
#, c-format
msgid "Error not expected but one was returned: %s"
msgstr "Seharusnya tidak ada error, tapi ini tiba-tiba ada error: %s"
#: ../src/ui/theme-viewer.c:1291
#, c-format
msgid "x value was %d, %d was expected"
msgstr "nilai x sebelumnya %d, padahal seharusnya %d"
#: ../src/ui/theme-viewer.c:1294
#, c-format
msgid "y value was %d, %d was expected"
msgstr "nilai y sebelumnya %d, padahal seharusnya %d"
#: ../src/ui/theme-viewer.c:1359
#, c-format
msgid "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
msgstr "ekspresi koordinat %d diambil dalam %g detik (rata-rata %g detik)\n"

1477
po/kk.po Normal file

File diff suppressed because it is too large Load Diff

458
po/ko.po
View File

@@ -18,8 +18,8 @@ msgstr ""
"Project-Id-Version: mutter\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?"
"product=mutter&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-01 15:50+0000\n"
"PO-Revision-Date: 2013-03-13 03:52+0900\n"
"POT-Creation-Date: 2013-08-18 20:03+0000\n"
"PO-Revision-Date: 2013-09-09 04:46+0900\n"
"Last-Translator: Changwoo Ryu <cwryu@debian.org>\n"
"Language-Team: GNOME Korea <gnome-kr@googlegroups.com>\n"
"Language: Korean\n"
@@ -218,7 +218,7 @@ msgstr "오른쪽 절반 뷰"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: ../src/compositor/compositor.c:507
#: ../src/compositor/compositor.c:589
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display \"%s"
@@ -227,11 +227,11 @@ msgstr ""
"다른 창 구성 관리 프로그램이 이미 디스플레이 \"%2$s\" 화면 %1$i번에서 실행 중"
"입니다."
#: ../src/compositor/meta-background.c:1111
#: ../src/compositor/meta-background.c:1076
msgid "background texture could not be created from file"
msgstr "파일에서 배경 텍스처를 만들 수 없습니다"
#: ../src/core/bell.c:320
#: ../src/core/bell.c:322
msgid "Bell event"
msgstr "삑소리 이벤트"
@@ -263,17 +263,17 @@ msgstr "기다리기(_W)"
msgid "_Force Quit"
msgstr "강제로 끝내기(_F)"
#: ../src/core/display.c:401
#: ../src/core/display.c:421
#, c-format
msgid "Missing %s extension required for compositing"
msgstr "콤포짓에 필요한 %s 확장 기능이 없습니다"
#: ../src/core/display.c:493
#: ../src/core/display.c:513
#, c-format
msgid "Failed to open X Window System display '%s'\n"
msgstr "X 윈도 시스템 디스플레이 '%s'을(를) 여는데 실패하였습니다\n"
#: ../src/core/keybindings.c:929
#: ../src/core/keybindings.c:1136
#, c-format
msgid ""
"Some other program is already using the key %s with modifiers %x as a "
@@ -282,41 +282,41 @@ msgstr ""
"다른 프로그램에서 이미 단축키로 변경 키 %2$x와(과) 키 %1$s을(를) 사용하고 있"
"습니다\n"
#: ../src/core/keybindings.c:1129
#: ../src/core/keybindings.c:1333
#, c-format
msgid "\"%s\" is not a valid accelerator\n"
msgstr "\"%s\"은(는) 올바른 단축키가 아닙니다\n"
#: ../src/core/main.c:196
#: ../src/core/main.c:197
msgid "Disable connection to session manager"
msgstr "세션 관리자와 연결 하지 않습니다"
#: ../src/core/main.c:202
#: ../src/core/main.c:203
msgid "Replace the running window manager"
msgstr "실행 중인 창 관리자를 바꿉니다"
#: ../src/core/main.c:208
#: ../src/core/main.c:209
msgid "Specify session management ID"
msgstr "세션 관리 ID를 지정합니다"
#: ../src/core/main.c:213
#: ../src/core/main.c:214
msgid "X Display to use"
msgstr "사용할 X 디스플레이"
#: ../src/core/main.c:219
#: ../src/core/main.c:220
msgid "Initialize session from savefile"
msgstr "저장 파일에서 세션을 초기화 합니다"
#: ../src/core/main.c:225
#: ../src/core/main.c:226
msgid "Make X calls synchronous"
msgstr "동기 X 호출을 합니다"
#: ../src/core/main.c:494
#: ../src/core/main.c:534
#, c-format
msgid "Failed to scan themes directory: %s\n"
msgstr "테마 디렉터리를 읽는 데 실패했습니다: %s\n"
#: ../src/core/main.c:510
#: ../src/core/main.c:550
#, c-format
msgid ""
"Could not find a theme! Be sure %s exists and contains the usual themes.\n"
@@ -324,6 +324,19 @@ msgstr ""
"테마를 찾을 수 없습니다! %s이(가) 있고 올바른 테마가 들어 있는지 확인하십시"
"오.\n"
#: ../src/core/monitor.c:711
msgid "Built-in display"
msgstr "내장 디스플레이"
#. 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"'
#.
#: ../src/core/monitor.c:739
#, c-format
msgid "Unknown %s"
msgstr "알 수 없는 %s인치"
#: ../src/core/mutter.c:40
#, c-format
msgid ""
@@ -347,18 +360,20 @@ msgstr "버전을 출력합니다"
msgid "Mutter plugin to use"
msgstr "사용할 머터 플러그인"
#: ../src/core/prefs.c:1087
#: ../src/core/prefs.c:1202
msgid ""
"Workarounds for broken applications disabled. Some applications may not "
"behave properly.\n"
msgstr "응용 프로그램에 대한 임시 방편을 막았습니다. 몇몇 응용 프로그램이 제대로 동작하지 않을것입니다.\n"
msgstr ""
"응용 프로그램에 대한 임시 방편을 막았습니다. 몇몇 응용 프로그램이 제대로 동작"
"하지 않을것입니다.\n"
#: ../src/core/prefs.c:1162
#: ../src/core/prefs.c:1277
#, c-format
msgid "Could not parse font description \"%s\" from GSettings key %s\n"
msgstr "GSettings 키 %2$s에서 글꼴 지정 \"%1$s\"을(를) 분석할 수 없습니다\n"
#: ../src/core/prefs.c:1228
#: ../src/core/prefs.c:1343
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for mouse button "
@@ -367,7 +382,7 @@ msgstr ""
"설정 데이터베이스에서 찾은 \"%s\"이(가) 마우스 단추 변경 키의 올바른 값이 아"
"닙니다\n"
#: ../src/core/prefs.c:1780
#: ../src/core/prefs.c:1909
#, c-format
msgid ""
"\"%s\" found in configuration database is not a valid value for keybinding "
@@ -376,17 +391,17 @@ msgstr ""
"설정 데이터베이스에서 찾은 \"%s\"이(가) 단축키 \"%s\"에 대한 올바른 값이 아닙"
"니다\n"
#: ../src/core/prefs.c:1879
#: ../src/core/prefs.c:1999
#, c-format
msgid "Workspace %d"
msgstr "작업 공간 %d"
#: ../src/core/screen.c:673
#: ../src/core/screen.c:534
#, c-format
msgid "Screen %d on display '%s' is invalid\n"
msgstr "디스플레이 '%2$s'의 화면 %1$d은(는) 잘못되었습니다\n"
#: ../src/core/screen.c:689
#: ../src/core/screen.c:550
#, c-format
msgid ""
"Screen %d on display \"%s\" already has a window manager; try using the --"
@@ -395,19 +410,19 @@ msgstr ""
"디스플레이 \"%2$s\"의 화면 %1$d에 이미 창 관리자가 실행되고 있습니다. 현재 "
"창 관리자를 무시하는 --replace 옵션을 써보십시오.\n"
#: ../src/core/screen.c:716
#: ../src/core/screen.c:577
#, c-format
msgid ""
"Could not acquire window manager selection on screen %d display \"%s\"\n"
msgstr "디스플레이 \"%2$s\"의 화면 %1$d에 창 관리 선택을 가질 수 없습니다\n"
#: ../src/core/screen.c:794
#: ../src/core/screen.c:655
#, c-format
msgid "Screen %d on display \"%s\" already has a window manager\n"
msgstr ""
"디스플레이 \"%2$s\"의 화면 %1$d은(는) 이미 창 관리자가 실행되고 있습니다\n"
#: ../src/core/screen.c:979
#: ../src/core/screen.c:846
#, c-format
msgid "Could not release screen %d on display \"%s\"\n"
msgstr "디스플레이 \"%2$s\"의 화면 %1$d을(를) 떼어 놓을수 없습니다\n"
@@ -467,44 +482,43 @@ msgstr ""
"이 창은 &quot;현재 설정 저장&quot;을 지원하지 않기 때문에 다음 번에 로그인 "
"할 때 수동으로 다시 시작해야 합니다."
#: ../src/core/util.c:80
#: ../src/core/util.c:84
#, c-format
msgid "Failed to open debug log: %s\n"
msgstr "디버그 로그 열기 실패: %s\n"
#: ../src/core/util.c:90
#: ../src/core/util.c:94
#, c-format
msgid "Failed to fdopen() log file %s: %s\n"
msgstr "로그 파일 %s을(를) fdopen()하기 실패: %s\n"
#: ../src/core/util.c:96
#: ../src/core/util.c:100
#, c-format
msgid "Opened log file %s\n"
msgstr "로그 파일 %s을(를) 엽니다\n"
#: ../src/core/util.c:115 ../src/tools/mutter-message.c:149
#, c-format
#: ../src/core/util.c:119
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "머터가 자세한 모드 지원 없이 컴파일 되었습니다\n"
#: ../src/core/util.c:259
#: ../src/core/util.c:264
msgid "Window manager: "
msgstr "창 관리자: "
#: ../src/core/util.c:407
#: ../src/core/util.c:414
msgid "Bug in window manager: "
msgstr "창 관리자의 벌레: "
#: ../src/core/util.c:438
#: ../src/core/util.c:445
msgid "Window manager warning: "
msgstr "창 관리자 주의: "
#: ../src/core/util.c:466
#: ../src/core/util.c:473
msgid "Window manager error: "
msgstr "장 관리자 오류: "
#. first time through
#: ../src/core/window.c:7539
#: ../src/core/window.c:7533
#, c-format
msgid ""
"Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER "
@@ -520,7 +534,7 @@ msgstr ""
#. * MWM but not WM_NORMAL_HINTS are basically broken. We complain
#. * about these apps but make them work.
#.
#: ../src/core/window.c:8263
#: ../src/core/window.c:8257
#, c-format
msgid ""
"Window %s sets an MWM hint indicating it isn't resizable, but sets min size "
@@ -529,23 +543,23 @@ msgstr ""
"%s 창에서 크기 변경이 불가능하다는 MWM 힌트를 설정했지만, 최소 크기 %d x %d "
"및 최대 크기 %d x %d(으)로 설정했습니다. 앞뒤가 맞지 않습니다.\n"
#: ../src/core/window-props.c:318
#: ../src/core/window-props.c:347
#, c-format
msgid "Application set a bogus _NET_WM_PID %lu\n"
msgstr "응용 프로그램이 가짜 _NET_WM_PID %lu을(를) 설정하였습니다\n"
# <창제목> (on <기계>)
#: ../src/core/window-props.c:434
#: ../src/core/window-props.c:463
#, c-format
msgid "%s (on %s)"
msgstr "%s (%s에서)"
#: ../src/core/window-props.c:1517
#: ../src/core/window-props.c:1546
#, c-format
msgid "Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n"
msgstr "%2$s에 대해 WM_TRANSIENT_FOR 0x%1$lx 창이 잘못되었습니다.\n"
#: ../src/core/window-props.c:1528
#: ../src/core/window-props.c:1557
#, c-format
msgid "WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n"
msgstr "%2$s에 대해 WM_TRANSIENT_FOR 0x%1$lx 창은 무한 반복입니다.\n"
@@ -574,9 +588,7 @@ msgstr "창 0x%2$lx의 등록 정보 %1$s은(는) 잘못된 UTF-8이 들어 있
#, c-format
msgid ""
"Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n"
msgstr ""
"창 0x%2$lx의 등록 정보 %1$s은(는) 목록안의 항목 %3$d에 잘못된 UTF-8을 포함하"
"고 있습니다\n"
msgstr "창 0x%2$lx의 등록 정보 %1$s은(는) 목록안의 항목 %3$d에 잘못된 UTF-8 문자가 들어 있습니다\n"
#: ../src/mutter.desktop.in.h:1 ../src/mutter-wm.desktop.in.h:1
msgid "Mutter"
@@ -705,109 +717,104 @@ msgstr "탭 팝업에서 창 선택"
msgid "Cancel tab popup"
msgstr "탭 팝업 취소"
#: ../src/tools/mutter-message.c:123
#, c-format
msgid "Usage: %s\n"
msgstr "사용법: %s\n"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:69
#: ../src/ui/menu.c:67
msgid "Mi_nimize"
msgstr "최소화(_N)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:71
#: ../src/ui/menu.c:69
msgid "Ma_ximize"
msgstr "최대화(_X)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:73
#: ../src/ui/menu.c:71
msgid "Unma_ximize"
msgstr "최대화 취소(_X)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:75
#: ../src/ui/menu.c:73
msgid "Roll _Up"
msgstr "말아올리기(_U)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:77
#: ../src/ui/menu.c:75
msgid "_Unroll"
msgstr "펼치기(_U)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:79
#: ../src/ui/menu.c:77
msgid "_Move"
msgstr "옮기기(_M)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:81
#: ../src/ui/menu.c:79
msgid "_Resize"
msgstr "크기 조정(_R)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:83
#: ../src/ui/menu.c:81
msgid "Move Titlebar On_screen"
msgstr "창 제목막대 화면에 표시(_S)"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:86 ../src/ui/menu.c:88
#: ../src/ui/menu.c:84 ../src/ui/menu.c:86
msgid "Always on _Top"
msgstr "항상 위(_T)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:90
#: ../src/ui/menu.c:88
msgid "_Always on Visible Workspace"
msgstr "항상 현재 작업 공간에 놓기(_A)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:92
#: ../src/ui/menu.c:90
msgid "_Only on This Workspace"
msgstr "이 작업 공간에만 놓기(_O)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:94
#: ../src/ui/menu.c:92
msgid "Move to Workspace _Left"
msgstr "왼쪽 작업 공간으로 옮기기(_L)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:96
#: ../src/ui/menu.c:94
msgid "Move to Workspace R_ight"
msgstr "오른쪽 작업 공간으로 옮기기(_I)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:98
#: ../src/ui/menu.c:96
msgid "Move to Workspace _Up"
msgstr "위쪽 작업 공간으로 옮기기(_U)"
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:100
#: ../src/ui/menu.c:98
msgid "Move to Workspace _Down"
msgstr "아래쪽 작업 공간으로 옮기기(_D)"
#. separator
#. Translators: Translate this string the same way as you do in libwnck!
#: ../src/ui/menu.c:104
#: ../src/ui/menu.c:102
msgid "_Close"
msgstr "닫기(_C)"
#: ../src/ui/menu.c:204
#: ../src/ui/menu.c:202
#, c-format
msgid "Workspace %d%n"
msgstr "작업 공간 %d%n"
#: ../src/ui/menu.c:214
#: ../src/ui/menu.c:212
#, c-format
msgid "Workspace 1_0"
msgstr "작업 공간 1_0"
#: ../src/ui/menu.c:216
#: ../src/ui/menu.c:214
#, c-format
msgid "Workspace %s%d"
msgstr "작업 공간 %s%d"
#: ../src/ui/menu.c:397
#: ../src/ui/menu.c:384
msgid "Move to Another _Workspace"
msgstr "다른 작업 공간으로 옮기기(_W)"
@@ -909,50 +916,50 @@ msgstr "Mod5"
msgid "%d x %d"
msgstr "%d x %d"
#: ../src/ui/theme.c:235
#: ../src/ui/theme.c:236
msgid "top"
msgstr "맨 위"
#: ../src/ui/theme.c:237
#: ../src/ui/theme.c:238
msgid "bottom"
msgstr "맨 아래"
#: ../src/ui/theme.c:239
#: ../src/ui/theme.c:240
msgid "left"
msgstr "왼쪽"
#: ../src/ui/theme.c:241
#: ../src/ui/theme.c:242
msgid "right"
msgstr "오른쪽"
#: ../src/ui/theme.c:269
#: ../src/ui/theme.c:270
#, c-format
msgid "frame geometry does not specify \"%s\" dimension"
msgstr "프레임 위치가 \"%s\"차원으로 지정되지 않았습니다"
#: ../src/ui/theme.c:288
#: ../src/ui/theme.c:289
#, c-format
msgid "frame geometry does not specify dimension \"%s\" for border \"%s\""
msgstr ""
"프레임 위치가 가장자리 \"%2$s\" 가장자리의 \"%1$s\"차원으로 지정되지 않았습니"
"다."
#: ../src/ui/theme.c:325
#: ../src/ui/theme.c:326
#, c-format
msgid "Button aspect ratio %g is not reasonable"
msgstr "단추의 가로세로 비 %g이(가) 적당하지 않습니다"
#: ../src/ui/theme.c:337
#: ../src/ui/theme.c:338
#, c-format
msgid "Frame geometry does not specify size of buttons"
msgstr "프레임 위치가 단추의 크기로 지정되지 않았습니다"
#: ../src/ui/theme.c:1050
#: ../src/ui/theme.c:1051
#, c-format
msgid "Gradients should have at least two colors"
msgstr "서서히 변하는 색으로 지정하려면 최소 2색이 필요합니다"
#: ../src/ui/theme.c:1202
#: ../src/ui/theme.c:1203
#, c-format
msgid ""
"GTK custom color specification must have color name and fallback in "
@@ -961,7 +968,7 @@ msgstr ""
"GTK 사용자 지정 색상 지정은 색 이름과 대체할 색을 괄호 안에 써야 합니다. 예"
"를 들어: gtk:custom(foo,bar). \"%s\"을(를) 분석할 수 없습니다"
#: ../src/ui/theme.c:1218
#: ../src/ui/theme.c:1219
#, c-format
msgid ""
"Invalid character '%c' in color_name parameter of gtk:custom, only A-Za-z0-9-"
@@ -970,7 +977,7 @@ msgstr ""
"gtk:custom의 color_name 파라미터 안에 잘못된 문자 '%c'. A-Za-z0-9-_ 문자만 허"
"용합니다."
#: ../src/ui/theme.c:1232
#: ../src/ui/theme.c:1233
#, c-format
msgid ""
"Gtk:custom format is \"gtk:custom(color_name,fallback)\", \"%s\" does not "
@@ -979,7 +986,7 @@ msgstr ""
"gtk:custom 형식은 \"gtk:custom(색이름,대체색)\"입니다, \"%s\"(은)는 형식에 맞"
"지 않습니다"
#: ../src/ui/theme.c:1277
#: ../src/ui/theme.c:1278
#, c-format
msgid ""
"GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] "
@@ -988,7 +995,7 @@ msgstr ""
"GTK 색상 지정은 중괄호안에 있어야 합니다. 예를 들어: gtk:fg[NORMAL], 여기서 "
"NORMAL이 값입니다. \"%s\"을(를) 분석할 수 없습니다."
#: ../src/ui/theme.c:1291
#: ../src/ui/theme.c:1292
#, c-format
msgid ""
"GTK color specification must have a close bracket after the state, e.g. gtk:"
@@ -997,17 +1004,17 @@ msgstr ""
"GTK 색상 지정은 값 뒤에 중괄호로 닫혀 있어야 합니다. 예를 들어: gtk:fg"
"[NORMAL], 여기서 NORMAL은 값입니다. \"%s\"을(를) 분석할 수 없습니다."
#: ../src/ui/theme.c:1302
#: ../src/ui/theme.c:1303
#, c-format
msgid "Did not understand state \"%s\" in color specification"
msgstr "색상 지정의 \"%s\" 값을 이해할 수 없습니다"
#: ../src/ui/theme.c:1315
#: ../src/ui/theme.c:1316
#, c-format
msgid "Did not understand color component \"%s\" in color specification"
msgstr "색상 지정의 색상 구성요소 \"%s\"을(를) 이해할 수 없습니다"
#: ../src/ui/theme.c:1344
#: ../src/ui/theme.c:1345
#, c-format
msgid ""
"Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the "
@@ -1016,17 +1023,17 @@ msgstr ""
"섞기 형식은 \"blend/bg_color/fg_color/alpha\"입니다, \"%s\"은(는) 형식에 맞"
"지 않습니다"
#: ../src/ui/theme.c:1355
#: ../src/ui/theme.c:1356
#, c-format
msgid "Could not parse alpha value \"%s\" in blended color"
msgstr "색상 섞기에서 알파 값 \"%s\"을(를) 분석할 수 없습니다"
#: ../src/ui/theme.c:1365
#: ../src/ui/theme.c:1366
#, c-format
msgid "Alpha value \"%s\" in blended color is not between 0.0 and 1.0"
msgstr "색상 섞기에서 알파 값 \"%s\"은(는) 0.0 과 1.0사이의 값이 아닙니다"
msgstr "색상 섞기에서 알파 값 \"%s\"은(는) 0.0과 1.0 사이의 값이 아닙니다"
#: ../src/ui/theme.c:1412
#: ../src/ui/theme.c:1413
#, c-format
msgid ""
"Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"
@@ -1034,79 +1041,78 @@ msgstr ""
"그림자 형식은 \"shade/base_color/format\"입니다, \"%s\"(은)는 형식에 맞지 않"
"습니다"
#: ../src/ui/theme.c:1423
#: ../src/ui/theme.c:1424
#, c-format
msgid "Could not parse shade factor \"%s\" in shaded color"
msgstr "그림자색에서 그림자 인자 \"%s\"(을)를 해석할 수 없습니다"
#: ../src/ui/theme.c:1433
#: ../src/ui/theme.c:1434
#, c-format
msgid "Shade factor \"%s\" in shaded color is negative"
msgstr "그림자색에서 그림자 인자 \"%s\"(은)는 음수입니다"
#: ../src/ui/theme.c:1462
#: ../src/ui/theme.c:1463
#, c-format
msgid "Could not parse color \"%s\""
msgstr "색상 \"%s\"을(를) 해석할 수 없습니다"
#: ../src/ui/theme.c:1779
#: ../src/ui/theme.c:1780
#, c-format
msgid "Coordinate expression contains character '%s' which is not allowed"
msgstr "좌표식에 허용되지 않는 문자 '%s'(이)가 포함되어 있습니다"
msgstr "좌표식에 허용되지 않는 문자 '%s'(이)가 어 있습니다"
#: ../src/ui/theme.c:1806
#: ../src/ui/theme.c:1807
#, c-format
msgid ""
"Coordinate expression contains floating point number '%s' which could not be "
"parsed"
msgstr "좌표식에 분석할 수 없는 부동소수점 숫자 '%s'이(가) 포함되어 있습니다"
#: ../src/ui/theme.c:1820
#: ../src/ui/theme.c:1821
#, c-format
msgid "Coordinate expression contains integer '%s' which could not be parsed"
msgstr "좌표식에 분석할 수 없는 정수 '%s'이(가) 포함되어 있습니다"
#: ../src/ui/theme.c:1941
#: ../src/ui/theme.c:1942
#, c-format
msgid ""
"Coordinate expression contained unknown operator at the start of this text: "
"\"%s\""
msgstr ""
"좌표식에 이 글자 시작부분에 알 수 없는 연산자가 포함되어 있습니다: \"%s\""
msgstr "좌표식에 이 글자 시작부분에 알 수 없는 연산자가 들어 있습니다: \"%s\""
#: ../src/ui/theme.c:1998
#: ../src/ui/theme.c:1999
#, c-format
msgid "Coordinate expression was empty or not understood"
msgstr "좌표식이 비어있거나 이해할 수 없습니다"
#: ../src/ui/theme.c:2111 ../src/ui/theme.c:2121 ../src/ui/theme.c:2155
#: ../src/ui/theme.c:2112 ../src/ui/theme.c:2122 ../src/ui/theme.c:2156
#, c-format
msgid "Coordinate expression results in division by zero"
msgstr "좌표식의 결과 값이 0로 나누었습니다"
#: ../src/ui/theme.c:2163
#: ../src/ui/theme.c:2164
#, c-format
msgid ""
"Coordinate expression tries to use mod operator on a floating-point number"
msgstr "좌표식에서 부동소수점 수에 나머지 연산을 하려 합니다"
#: ../src/ui/theme.c:2219
#: ../src/ui/theme.c:2220
#, c-format
msgid ""
"Coordinate expression has an operator \"%s\" where an operand was expected"
msgstr "좌표식에서 피연산자가 들어갈 곳에 연산자 \"%s\"이(가) 있습니다"
#: ../src/ui/theme.c:2228
#: ../src/ui/theme.c:2229
#, c-format
msgid "Coordinate expression had an operand where an operator was expected"
msgstr "좌표식에서 연산자가 들어갈 곳에 피연산자가 있습니다"
#: ../src/ui/theme.c:2236
#: ../src/ui/theme.c:2237
#, c-format
msgid "Coordinate expression ended with an operator instead of an operand"
msgstr "좌표식에서 피연산자 대신에 연산자로 끝나있습니다"
#: ../src/ui/theme.c:2246
#: ../src/ui/theme.c:2247
#, c-format
msgid ""
"Coordinate expression has operator \"%c\" following operator \"%c\" with no "
@@ -1115,37 +1121,37 @@ msgstr ""
"좌표식에서 피연산자가 없는 연산자 \"%2$c\"다음에 연산자 \"%1$c\"이(가) 있습니"
"다"
#: ../src/ui/theme.c:2397 ../src/ui/theme.c:2442
#: ../src/ui/theme.c:2398 ../src/ui/theme.c:2443
#, c-format
msgid "Coordinate expression had unknown variable or constant \"%s\""
msgstr "좌표식에 알 수 없는 변수나 상수 \"%s\"이(가) 있습니다"
#: ../src/ui/theme.c:2496
#: ../src/ui/theme.c:2497
#, c-format
msgid "Coordinate expression parser overflowed its buffer."
msgstr "좌표 계산 파서의 버퍼가 크기를 넘어갔습니다."
#: ../src/ui/theme.c:2525
#: ../src/ui/theme.c:2526
#, c-format
msgid "Coordinate expression had a close parenthesis with no open parenthesis"
msgstr "좌표식에 닫는 괄호는 있지만 여는 괄호가 없습니다"
#: ../src/ui/theme.c:2589
#: ../src/ui/theme.c:2590
#, c-format
msgid "Coordinate expression had an open parenthesis with no close parenthesis"
msgstr "좌표식에 여는 괄호는 있지만 닫는 괄호가 없습니다"
#: ../src/ui/theme.c:2600
#: ../src/ui/theme.c:2601
#, c-format
msgid "Coordinate expression doesn't seem to have any operators or operands"
msgstr "좌표식에 어떠한 연산자나 피연산자가 없습니다"
#: ../src/ui/theme.c:2813 ../src/ui/theme.c:2833 ../src/ui/theme.c:2853
#: ../src/ui/theme.c:2814 ../src/ui/theme.c:2834 ../src/ui/theme.c:2854
#, c-format
msgid "Theme contained an expression that resulted in an error: %s\n"
msgstr "테마가 오류 값을 내는 표현식이 들어 있습니다: %s\n"
#: ../src/ui/theme.c:4499
#: ../src/ui/theme.c:4500
#, c-format
msgid ""
"<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be "
@@ -1154,7 +1160,7 @@ msgstr ""
"이 프레임 스타일에는 <button function=\"%s\" style=\"%s\" draw_ops=\"whatever"
"\"/>가 지정되어야 합니다"
#: ../src/ui/theme.c:5010 ../src/ui/theme.c:5035
#: ../src/ui/theme.c:5011 ../src/ui/theme.c:5036
#, c-format
msgid ""
"Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"
@@ -1162,18 +1168,18 @@ msgstr ""
"<frame state=\"%s\" resize=\"%s\" focus=\"%s\" state=\"whatever\"/> 가 없습니"
"다"
#: ../src/ui/theme.c:5083
#: ../src/ui/theme.c:5082
#, c-format
msgid "Failed to load theme \"%s\": %s\n"
msgstr "테마 \"%s\"을(를) 읽을 수 없습니다: %s\n"
#: ../src/ui/theme.c:5219 ../src/ui/theme.c:5226 ../src/ui/theme.c:5233
#: ../src/ui/theme.c:5240 ../src/ui/theme.c:5247
#: ../src/ui/theme.c:5218 ../src/ui/theme.c:5225 ../src/ui/theme.c:5232
#: ../src/ui/theme.c:5239 ../src/ui/theme.c:5246
#, c-format
msgid "No <%s> set for theme \"%s\""
msgstr "테마 \"%2$s\"의 <%1$s>(이)가 설정되지 않았습니다"
#: ../src/ui/theme.c:5255
#: ../src/ui/theme.c:5254
#, c-format
msgid ""
"No frame style set for window type \"%s\" in theme \"%s\", add a <window "
@@ -1182,14 +1188,14 @@ msgstr ""
"테마 \"%2$s\"의 창 형식 \"%1$s\"에 대한 프레임 스타일이 없습니다,<window "
"type=\"%3$s\" style_set=\"whatever\"/> 엘리먼트를 추가하십시오"
#: ../src/ui/theme.c:5662 ../src/ui/theme.c:5724 ../src/ui/theme.c:5787
#: ../src/ui/theme.c:5661 ../src/ui/theme.c:5723 ../src/ui/theme.c:5786
#, c-format
msgid ""
"User-defined constants must begin with a capital letter; \"%s\" does not"
msgstr ""
"사용자 정의 상수는 대문자로 시작되어야 합니다. \"%s\"은(는) 그렇지 않습니다."
#: ../src/ui/theme.c:5670 ../src/ui/theme.c:5732 ../src/ui/theme.c:5795
#: ../src/ui/theme.c:5669 ../src/ui/theme.c:5731 ../src/ui/theme.c:5794
#, c-format
msgid "Constant \"%s\" has already been defined"
msgstr "상수 \"%s\"은(는) 이미 지정되어 있습니다"
@@ -1324,9 +1330,7 @@ msgstr "<%s> 엘리먼트는 <%s> 아래에 허용되지 않습니다"
msgid ""
"Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" "
"for buttons"
msgstr ""
"단추의 button_width/button_height 와 \"aspect_ratio\"를 한꺼번에 지정할 수 없"
"습니다"
msgstr "단추의 \"button_width\"/\"button_height\"와 \"aspect_ratio\"를 한꺼번에 지정할 수 없습니다"
#: ../src/ui/theme-parser.c:1450
#, c-format
@@ -1387,7 +1391,7 @@ msgstr "\"%s\"라 불리는 <draw_ops>는 정의되지 않았습니다"
#: ../src/ui/theme-parser.c:2706 ../src/ui/theme-parser.c:2802
#, c-format
msgid "Including draw_ops \"%s\" here would create a circular reference"
msgstr "draw_ops를 포함하는 \"%s\"이(가) 자기 자신을 참조하고 있습니다"
msgstr "여기서 draw_ops \"%s\"을(를) 포함하면 순환 참조가 됩니다."
#: ../src/ui/theme-parser.c:2917
#, c-format
@@ -1569,205 +1573,7 @@ msgstr "<%s> 엘리먼트 안에 텍스트가 허용되지 않습니다"
msgid "<%s> specified twice for this theme"
msgstr "이 테마에서 <%s> 태그가 두 번 지정되었습니다"
#: ../src/ui/theme-parser.c:4334
#: ../src/ui/theme-parser.c:4336
#, c-format
msgid "Failed to find a valid file for theme %s\n"
msgstr "%s 테마의 올바른 파일을 찾는 데 실패했습니다\n"
#: ../src/ui/theme-viewer.c:99
msgid "_Windows"
msgstr "창(_W)"
#: ../src/ui/theme-viewer.c:100
msgid "_Dialog"
msgstr "대화 상자(_D)"
#: ../src/ui/theme-viewer.c:101
msgid "_Modal dialog"
msgstr "모달 대화 상자(_M)"
#: ../src/ui/theme-viewer.c:102
msgid "_Utility"
msgstr "도구(_U)"
#: ../src/ui/theme-viewer.c:103
msgid "_Splashscreen"
msgstr "스플래시 화면(_S)"
#: ../src/ui/theme-viewer.c:104
msgid "_Top dock"
msgstr "위 도크(_T)"
#: ../src/ui/theme-viewer.c:105
msgid "_Bottom dock"
msgstr "아래 도크(_B)"
#: ../src/ui/theme-viewer.c:106
msgid "_Left dock"
msgstr "왼쪽 도크(_L)"
#: ../src/ui/theme-viewer.c:107
msgid "_Right dock"
msgstr "오른쪽 도크(_R)"
#: ../src/ui/theme-viewer.c:108
msgid "_All docks"
msgstr "모든 도크(_A)"
#: ../src/ui/theme-viewer.c:109
msgid "Des_ktop"
msgstr "데스크톱(_K)"
#: ../src/ui/theme-viewer.c:115
msgid "Open another one of these windows"
msgstr "이 창을 하나 더 엽니다"
#: ../src/ui/theme-viewer.c:117
msgid "This is a demo button with an 'open' icon"
msgstr "'열기' 아이콘이 들어 있는 데모 단추입니다"
#: ../src/ui/theme-viewer.c:119
msgid "This is a demo button with a 'quit' icon"
msgstr "'끝내기' 아이콘이 들어 있는 데모 단추입니다"
#: ../src/ui/theme-viewer.c:248
msgid "This is a sample message in a sample dialog"
msgstr "예제 대화 상자의 예제 메시지입니다"
#: ../src/ui/theme-viewer.c:328
#, c-format
msgid "Fake menu item %d\n"
msgstr "가짜 메뉴 항목 %d\n"
#: ../src/ui/theme-viewer.c:363
msgid "Border-only window"
msgstr "테두리만 있는 창"
#: ../src/ui/theme-viewer.c:365
msgid "Bar"
msgstr "모음"
#: ../src/ui/theme-viewer.c:382
msgid "Normal Application Window"
msgstr "보통 프로그램 창"
#: ../src/ui/theme-viewer.c:386
msgid "Dialog Box"
msgstr "대화 상자"
#: ../src/ui/theme-viewer.c:390
msgid "Modal Dialog Box"
msgstr "모달 대화 상자"
#: ../src/ui/theme-viewer.c:394
msgid "Utility Palette"
msgstr "도구 팔레트"
#: ../src/ui/theme-viewer.c:398
msgid "Torn-off Menu"
msgstr "떼어내기 메뉴"
#: ../src/ui/theme-viewer.c:402
msgid "Border"
msgstr "테두리"
#: ../src/ui/theme-viewer.c:406
msgid "Attached Modal Dialog"
msgstr "부착한 모달 대화 상자"
#: ../src/ui/theme-viewer.c:737
#, c-format
msgid "Button layout test %d"
msgstr "단추 배치 테스트 %d"
#: ../src/ui/theme-viewer.c:766
#, c-format
msgid "%g milliseconds to draw one window frame"
msgstr "창 프레임 하나를 그리는 데 %g ms"
#: ../src/ui/theme-viewer.c:811
#, c-format
msgid "Usage: metacity-theme-viewer [THEMENAME]\n"
msgstr "사용법: metacity-theme-viewer [테마이름]\n"
#: ../src/ui/theme-viewer.c:818
#, c-format
msgid "Error loading theme: %s\n"
msgstr "테마를 읽어들이는 데 오류가 발생했습니다: %s\n"
#: ../src/ui/theme-viewer.c:824
#, c-format
msgid "Loaded theme \"%s\" in %g seconds\n"
msgstr "\"%s\" 테마를 읽어들이는 데 %g초\n"
#: ../src/ui/theme-viewer.c:869
msgid "Normal Title Font"
msgstr "보통 제목 글꼴"
#: ../src/ui/theme-viewer.c:875
msgid "Small Title Font"
msgstr "작은 제목 글꼴"
#: ../src/ui/theme-viewer.c:881
msgid "Large Title Font"
msgstr "큰 제목 글꼴"
#: ../src/ui/theme-viewer.c:886
msgid "Button Layouts"
msgstr "단추 배치"
#: ../src/ui/theme-viewer.c:891
msgid "Benchmark"
msgstr "벤치마크"
#: ../src/ui/theme-viewer.c:947
msgid "Window Title Goes Here"
msgstr "창 제목이 여기에 들어갑니다"
#: ../src/ui/theme-viewer.c:1053
#, c-format
msgid ""
"Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g "
"seconds wall clock time including X server resources (%g milliseconds per "
"frame)\n"
msgstr ""
"%d개 프레임을 그리는 데 클라이언트 입장에서 %g초가 걸렸습니다(한 프레임에 %g "
"ms). 그리고 X 서버 리소스까지 포함해 실제 시간으로 %g 초가 걸렸습니다(한 프레"
"임에 %g ms).\n"
#: ../src/ui/theme-viewer.c:1273
msgid "position expression test returned TRUE but set error"
msgstr "위치 표현식 테스트가 참을 리턴했지만 오류가 발생했습니다"
#: ../src/ui/theme-viewer.c:1275
msgid "position expression test returned FALSE but didn't set error"
msgstr "위치 표현식 테스트가 거짓을 리턴했지만 오류가 발생하지 않았습니다"
#: ../src/ui/theme-viewer.c:1279
msgid "Error was expected but none given"
msgstr "오류가 발생해야 하지만 발생하지 않았습니다"
#: ../src/ui/theme-viewer.c:1281
#, c-format
msgid "Error %d was expected but %d given"
msgstr "오류 %d번이 발생해야 하지만 오류 %d번이 발생했습니다"
#: ../src/ui/theme-viewer.c:1287
#, c-format
msgid "Error not expected but one was returned: %s"
msgstr "오류가 발생하면 안 되지만 오류 한 개가 발생했습니다: %s"
#: ../src/ui/theme-viewer.c:1291
#, c-format
msgid "x value was %d, %d was expected"
msgstr "가로값이 %d입니다. 와야 하는 값은 %d입니다"
#: ../src/ui/theme-viewer.c:1294
#, c-format
msgid "y value was %d, %d was expected"
msgstr "세로값이 %d입니다. 와야 하는 값은 %d입니다"
#: ../src/ui/theme-viewer.c:1359
#, c-format
msgid "%d coordinate expressions parsed in %g seconds (%g seconds average)\n"
msgstr "좌표 표현식 %d개를 %g초에 파싱했습니다(평균 %g초)\n"

498
po/lv.po

File diff suppressed because it is too large Load Diff

493
po/pa.po

File diff suppressed because it is too large Load Diff

921
po/ru.po

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: mutter\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=mutter"
"&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-01 15:50+0000\n"
"PO-Revision-Date: 2013-03-11 11:40+0200\n"
"POT-Creation-Date: 2013-08-18 20:03+0000\n"
"PO-Revision-Date: 2013-09-06 09:19+0200\n"
"Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian <gnom@prevod.org>\n"
"Language: sr\n"
@@ -320,6 +320,20 @@ msgstr ""
"Не могу да пронађем тему! Проверите да „%s“ постоји и да садржи уобичајене "
"теме.\n"
#: ../src/core/monitor.c:711
msgid "Built-in display"
msgstr "Уграђени дисплеј"
#. 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"'
#.
#: ../src/core/monitor.c:739
#, c-format
#| msgid "Unknown element %s"
msgid "Unknown %s"
msgstr "Непознат %s"
#: ../src/core/mutter.c:40
#, c-format
msgid ""

View File

@@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: mutter\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=mutter"
"&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-01 15:50+0000\n"
"PO-Revision-Date: 2013-03-11 11:40+0200\n"
"POT-Creation-Date: 2013-08-18 20:03+0000\n"
"PO-Revision-Date: 2013-09-06 09:19+0200\n"
"Last-Translator: Miroslav Nikolić <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian <gnom@prevod.org>\n"
"Language: sr\n"
@@ -320,6 +320,20 @@ msgstr ""
"Ne mogu da pronađem temu! Proverite da „%s“ postoji i da sadrži uobičajene "
"teme.\n"
#: ../src/core/monitor.c:711
msgid "Built-in display"
msgstr "Ugrađeni displej"
#. 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"'
#.
#: ../src/core/monitor.c:739
#, c-format
#| msgid "Unknown element %s"
msgid "Unknown %s"
msgstr "Nepoznat %s"
#: ../src/core/mutter.c:40
#, c-format
msgid ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

30
protocol/gtk-shell.xml Normal file
View File

@@ -0,0 +1,30 @@
<protocol name="gtk">
<interface name="gtk_shell" version="1">
<enum name="capability">
<entry name="global_app_menu" value="1"/>
<entry name="global_menu_bar" value="2"/>
</enum>
<event name="capabilities">
<arg name="capabilities" type="uint"/>
</event>
<request name="get_gtk_surface">
<arg name="gtk_surface" type="new_id" interface="gtk_surface"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
</interface>
<interface name="gtk_surface" version="1">
<request name="set_dbus_properties">
<arg name="application_id" type="string" allow-null="true"/>
<arg name="app_menu_path" type="string" allow-null="true"/>
<arg name="menubar_path" type="string" allow-null="true"/>
<arg name="window_object_path" type="string" allow-null="true"/>
<arg name="application_object_path" type="string" allow-null="true"/>
<arg name="unique_bus_name" type="string" allow-null="true"/>
</request>
</interface>
</protocol>

View File

@@ -40,6 +40,9 @@ mutter_built_sources = \
$(dbus_xrandr_built_sources) \
mutter-enum-types.h \
mutter-enum-types.c \
wayland/gtk-shell-protocol.c \
wayland/gtk-shell-server-protocol.h \
wayland/gtk-shell-client-protocol.h \
wayland/xserver-protocol.c \
wayland/xserver-server-protocol.h \
wayland/xserver-client-protocol.h
@@ -131,6 +134,7 @@ libmutter_wayland_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 \
@@ -150,6 +154,7 @@ libmutter_wayland_la_SOURCES = \
core/stack-tracker.h \
core/util.c \
meta/util.h \
core/util-private.h \
core/window-props.c \
core/window-props.h \
core/window.c \
@@ -195,7 +200,13 @@ libmutter_wayland_la_SOURCES += \
wayland/meta-wayland-seat.c \
wayland/meta-wayland-seat.h \
wayland/meta-wayland-stage.h \
wayland/meta-wayland-stage.c
wayland/meta-wayland-stage.c \
wayland/meta-wayland-surface.c \
wayland/meta-wayland-surface.h \
wayland/meta-wayland-types.h \
wayland/meta-wayland-versions.h \
wayland/meta-weston-launch.c \
wayland/meta-weston-launch.h
libmutter_wayland_la_LDFLAGS = -no-undefined
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
@@ -247,6 +258,17 @@ bin_PROGRAMS=mutter-wayland
mutter_wayland_SOURCES = core/mutter.c
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
bin_PROGRAMS+=mutter-launch
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
install-exec-hook:
-chown root $(DESTDIR)$(bindir)/mutter-launch
-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
if HAVE_INTROSPECTION
include $(INTROSPECTION_MAKEFILE)
@@ -306,7 +328,7 @@ xml_DATA = $(xml_in_files:.xml.in=.xml)
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@
@GSETTINGS_RULES@
@@ -317,6 +339,7 @@ CLEANFILES = \
mutter-wayland.desktop \
mutter-wm.desktop \
org.gnome.mutter.gschema.xml \
org.gnome.mutter.wayland.gschema.xml \
$(xml_DATA) \
$(mutter_built_sources) \
$(typelib_DATA) \
@@ -333,10 +356,12 @@ EXTRA_DIST=$(desktopfiles_files) \
$(wmproperties_in_files) \
$(xml_in_files) \
org.gnome.mutter.gschema.xml.in \
org.gnome.mutter.wayland.gschema.xml.in \
mutter-schemas.convert \
libmutter-wayland.pc.in \
mutter-enum-types.h.in \
mutter-enum-types.c.in
mutter-enum-types.c.in \
xrandr.xml idle-monitor.xml
BUILT_SOURCES = $(mutter_built_sources)
MUTTER_STAMP_FILES = stamp-mutter-enum-types.h

View File

@@ -50,7 +50,7 @@ meta_create_color_texture_4ub (guint8 red,
CoglColor color;
guint8 pixel[4];
cogl_color_set_from_4ub (&color, red, green, blue, alpha);
cogl_color_init_from_4ub (&color, red, green, blue, alpha);
cogl_color_premultiply (&color);
pixel[0] = cogl_color_get_red_byte (&color);
@@ -73,10 +73,8 @@ meta_create_color_texture_4ub (guint8 red,
* @src_texture: (allow-none): texture to use initially for the layer
*
* Creates a pipeline with a single layer. Using a common template
* allows sharing a shader for different uses in Mutter. To share the same
* shader with all other pipelines that are just texture plus opacity
* would require Cogl fixes.
* (See http://bugzilla.clutter-project.org/show_bug.cgi?id=2425)
* makes it easier for Cogl to share a shader for different uses in
* Mutter.
*
* Return value: (transfer full): a newly created #CoglPipeline
*/
@@ -86,22 +84,21 @@ meta_create_texture_pipeline (CoglTexture *src_texture)
static CoglPipeline *texture_pipeline_template = NULL;
CoglPipeline *pipeline;
/* We use a pipeline that has a dummy texture as a base for all
texture pipelines. The idea is that only the Cogl texture object
would be different in the children so it is likely that Cogl will
be able to share GL programs between all the textures. */
/* The only state used in the pipeline that would affect the shader
generation is the texture type on the layer. Therefore we create
a template pipeline which sets this state and all texture
pipelines are created as a copy of this. That way Cogl can find
the shader state for the pipeline more quickly by looking at the
pipeline ancestry instead of resorting to the shader cache. */
if (G_UNLIKELY (texture_pipeline_template == NULL))
{
CoglTexture *dummy_texture;
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
dummy_texture = meta_create_color_texture_4ub (0xff, 0xff, 0xff, 0xff,
COGL_TEXTURE_NONE);
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
texture_pipeline_template = cogl_pipeline_new (ctx);
cogl_pipeline_set_layer_texture (texture_pipeline_template, 0, dummy_texture);
cogl_object_unref (dummy_texture);
cogl_pipeline_set_layer_null_texture (texture_pipeline_template,
0, /* layer */
COGL_TEXTURE_TYPE_2D);
}
pipeline = cogl_pipeline_copy (texture_pipeline_template);

View File

@@ -84,7 +84,10 @@
#include "meta-window-group.h"
#include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */
#include "util-private.h"
#include "meta-wayland-private.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-keyboard.h"
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
@@ -424,34 +427,20 @@ meta_stage_is_focused (MetaScreen *screen)
return (screen->display->focus_type == META_FOCUS_STAGE);
}
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
static gboolean
begin_modal_x11 (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);
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;
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;
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
@@ -501,14 +490,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
keyboard_grabbed = TRUE;
}
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->grab_window = NULL;
display->grab_screen = screen;
display->grab_have_pointer = TRUE;
display->grab_have_keyboard = TRUE;
compositor->modal_plugin = plugin;
return TRUE;
fail:
@@ -520,6 +501,80 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
return FALSE;
}
static gboolean
begin_modal_wayland (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaWaylandCompositor *compositor;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
compositor = meta_wayland_compositor_get_default ();
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
goto fail;
pointer_grabbed = TRUE;
}
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
timestamp))
goto fail;
keyboard_grabbed = TRUE;
}
return TRUE;
fail:
if (pointer_grabbed)
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
if (keyboard_grabbed)
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
return FALSE;
}
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
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;
display->grab_have_pointer = TRUE;
display->grab_have_keyboard = TRUE;
compositor->modal_plugin = plugin;
return TRUE;
}
void
meta_end_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
@@ -531,8 +586,19 @@ meta_end_modal_for_plugin (MetaScreen *screen,
g_return_if_fail (compositor->modal_plugin == plugin);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
timestamp);
}
else
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
}
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL;
@@ -629,7 +695,7 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
MetaCompScreen *info;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
Window xwin;
Window xwin = None;
gint width, height;
MetaWaylandCompositor *wayland_compositor;
@@ -930,8 +996,8 @@ is_grabbed_event (MetaDisplay *display,
}
void
meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
MetaWindow *window)
meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window)
{
MetaWindowActor *window_actor;
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
@@ -1001,10 +1067,7 @@ meta_compositor_process_event (MetaCompositor *compositor,
{
if (compositor->modal_plugin && is_grabbed_event (compositor->display, event))
{
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (compositor->modal_plugin);
if (klass->xevent_filter)
klass->xevent_filter (compositor->modal_plugin, event);
_meta_plugin_xevent_filter (compositor->modal_plugin, event);
/* We always consume events even if the plugin says it didn't handle them;
* exclusive is exclusive */
@@ -1210,6 +1273,7 @@ sync_actor_stacking (MetaCompScreen *info)
* we go ahead and do it */
children = clutter_actor_get_children (info->window_group);
has_windows = FALSE;
reordered = FALSE;
/* We allow for actors in the window group other than the actors we

View File

@@ -6,9 +6,9 @@
#include <meta/screen.h>
#include <meta/meta-background-actor.h>
void meta_background_actor_set_visible_region (MetaBackgroundActor *self,
cairo_region_t *visible_region);
void meta_background_actor_set_clip_region (MetaBackgroundActor *self,
cairo_region_t *clip_region);
cairo_region_t *meta_background_actor_get_visible_region (MetaBackgroundActor *self);
cairo_region_t *meta_background_actor_get_clip_region (MetaBackgroundActor *self);
#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */

View File

@@ -44,7 +44,7 @@
struct _MetaBackgroundActorPrivate
{
cairo_region_t *visible_region;
cairo_region_t *clip_region;
};
G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
@@ -54,7 +54,7 @@ meta_background_actor_dispose (GObject *object)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
meta_background_actor_set_visible_region (self, NULL);
meta_background_actor_set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
}
@@ -167,17 +167,17 @@ meta_background_actor_new (void)
}
/**
* meta_background_actor_set_visible_region:
* meta_background_actor_set_clip_region:
* @self: a #MetaBackgroundActor
* @visible_region: (allow-none): the area of the actor (in allocate-relative
* @clip_region: (allow-none): the area of the actor (in allocate-relative
* coordinates) that is visible.
*
* Sets the area of the background that is unobscured by overlapping windows.
* This is used to optimize and only paint the visible portions.
*/
void
meta_background_actor_set_visible_region (MetaBackgroundActor *self,
cairo_region_t *visible_region)
meta_background_actor_set_clip_region (MetaBackgroundActor *self,
cairo_region_t *clip_region)
{
MetaBackgroundActorPrivate *priv;
@@ -185,16 +185,16 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self,
priv = self->priv;
g_clear_pointer (&priv->visible_region,
g_clear_pointer (&priv->clip_region,
(GDestroyNotify)
cairo_region_destroy);
if (visible_region)
priv->visible_region = cairo_region_copy (visible_region);
if (clip_region)
priv->clip_region = cairo_region_copy (clip_region);
}
/**
* meta_background_actor_get_visible_region:
* meta_background_actor_get_clip_region:
* @self: a #MetaBackgroundActor
*
* Return value (transfer full): a #cairo_region_t that represents the part of
@@ -202,16 +202,16 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self,
* #MetaWindowActor objects.
*/
cairo_region_t *
meta_background_actor_get_visible_region (MetaBackgroundActor *self)
meta_background_actor_get_clip_region (MetaBackgroundActor *self)
{
MetaBackgroundActorPrivate *priv = self->priv;
ClutterActorBox content_box;
cairo_rectangle_int_t content_area = { 0 };
cairo_region_t *visible_region;
cairo_region_t *clip_region;
g_return_val_if_fail (META_IS_BACKGROUND_ACTOR (self), NULL);
if (!priv->visible_region)
if (!priv->clip_region)
return NULL;
clutter_actor_get_content_box (CLUTTER_ACTOR (self), &content_box);
@@ -221,8 +221,8 @@ meta_background_actor_get_visible_region (MetaBackgroundActor *self)
content_area.width = content_box.x2 - content_box.x1;
content_area.height = content_box.y2 - content_box.y1;
visible_region = cairo_region_create_rectangle (&content_area);
cairo_region_intersect (visible_region, priv->visible_region);
clip_region = cairo_region_create_rectangle (&content_area);
cairo_region_intersect (clip_region, priv->clip_region);
return visible_region;
return clip_region;
}

View File

@@ -6,6 +6,6 @@
#include <meta/screen.h>
#include <meta/meta-background-group.h>
void meta_background_group_set_visible_region (MetaBackgroundGroup *self,
cairo_region_t *visible_region);
void meta_background_group_set_clip_region (MetaBackgroundGroup *self,
cairo_region_t *visible_region);
#endif /* META_BACKGROUND_GROUP_PRIVATE_H */

View File

@@ -62,16 +62,16 @@ meta_background_group_init (MetaBackgroundGroup *self)
}
/**
* meta_background_group_set_visible_region:
* meta_background_group_set_clip_region:
* @self: a #MetaBackgroundGroup
* @visible_region: (allow-none): the parts of the background to paint
* @region: (allow-none): the parts of the background to paint
*
* Sets the area of the backgrounds that is unobscured by overlapping windows.
* This is used to optimize and only paint the visible portions.
*/
void
meta_background_group_set_visible_region (MetaBackgroundGroup *self,
cairo_region_t *region)
meta_background_group_set_clip_region (MetaBackgroundGroup *self,
cairo_region_t *region)
{
GList *children, *l;
@@ -82,7 +82,7 @@ meta_background_group_set_visible_region (MetaBackgroundGroup *self,
if (META_IS_BACKGROUND_ACTOR (actor))
{
meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (actor), region);
meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (actor), region);
}
else if (META_IS_BACKGROUND_GROUP (actor))
{
@@ -92,7 +92,7 @@ meta_background_group_set_visible_region (MetaBackgroundGroup *self,
continue;
cairo_region_translate (region, -x, -y);
meta_background_group_set_visible_region (META_BACKGROUND_GROUP (actor), region);
meta_background_group_set_clip_region (META_BACKGROUND_GROUP (actor), region);
cairo_region_translate (region, x, y);
}
}

View File

@@ -37,6 +37,7 @@
#include "mutter-enum-types.h"
#include <meta/errors.h>
#include <meta/meta-background.h>
#include "util-private.h"
#include "meta-background-actor-private.h"
#define FRAGMENT_SHADER_DECLARATIONS \
@@ -412,13 +413,13 @@ meta_background_paint_content (ClutterContent *content,
*/
if (META_IS_BACKGROUND_ACTOR (actor))
{
cairo_region_t *visible_region;
visible_region = meta_background_actor_get_visible_region (META_BACKGROUND_ACTOR (actor));
cairo_region_t *clip_region;
clip_region = meta_background_actor_get_clip_region (META_BACKGROUND_ACTOR (actor));
if (visible_region != NULL)
if (clip_region != NULL)
{
cairo_region_intersect (paintable_region, visible_region);
cairo_region_destroy (visible_region);
cairo_region_intersect (paintable_region, clip_region);
cairo_region_destroy (clip_region);
}
}

View File

@@ -192,10 +192,7 @@ meta_module_class_init (MetaModuleClass *klass)
static void
meta_module_init (MetaModule *self)
{
MetaModulePrivate *priv;
self->priv = priv = META_MODULE_GET_PRIVATE (self);
self->priv = META_MODULE_GET_PRIVATE (self);
}
GType

View File

@@ -306,41 +306,13 @@ meta_plugin_manager_filter_keybinding (MetaPluginManager *plugin_mgr,
return FALSE;
}
/*
* The public method that the compositor hooks into for desktop switching.
*
* Returns TRUE if the plugin handled the event type (i.e.,
* if the return value is FALSE, there will be no subsequent call to the
* manager completed() callback, and the compositor must ensure that any
* appropriate post-effect cleanup is carried out.
*/
gboolean
meta_plugin_manager_xevent_filter (MetaPluginManager *plugin_mgr,
XEvent *xev)
{
MetaPlugin *plugin = plugin_mgr->plugin;
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
/* We need to make sure that clutter gets certain events, like
* ConfigureNotify on the stage window. If there is a plugin that
* provides an xevent_filter function, then it's the responsibility
* of that plugin to pass events to Clutter. Otherwise, we send the
* event directly to Clutter ourselves.
*/
if (klass->xevent_filter)
return klass->xevent_filter (plugin, xev);
/* When mutter is running as a wayland compositor, things like input
* events just come directly from clutter so it won't have disabled
* clutter's event retrieval and won't need to forward it events (if
* it did it would lead to recursion). Also when running as a
* wayland compositor we shouldn't be assuming that we're running
* with the clutter x11 backend.
*/
if (meta_is_wayland_compositor ())
return FALSE;
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
return _meta_plugin_xevent_filter (plugin, xev);
}
void

View File

@@ -72,6 +72,8 @@ gboolean meta_plugin_manager_filter_keybinding (MetaPluginManager *mgr,
gboolean meta_plugin_manager_xevent_filter (MetaPluginManager *mgr,
XEvent *xev);
gboolean _meta_plugin_xevent_filter (MetaPlugin *plugin,
XEvent *xev);
void meta_plugin_manager_confirm_display_change (MetaPluginManager *mgr);

View File

@@ -138,9 +138,7 @@ meta_plugin_class_init (MetaPluginClass *klass)
static void
meta_plugin_init (MetaPlugin *self)
{
MetaPluginPrivate *priv;
self->priv = priv = META_PLUGIN_GET_PRIVATE (self);
self->priv = META_PLUGIN_GET_PRIVATE (self);
}
gboolean
@@ -185,6 +183,28 @@ _meta_plugin_effect_started (MetaPlugin *plugin)
priv->running++;
}
gboolean
_meta_plugin_xevent_filter (MetaPlugin *plugin,
XEvent *xev)
{
MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
/* When mutter is running as a wayland compositor, things like input
* events just come directly from clutter so it won't have disabled
* clutter's event retrieval and won't need to forward it events (if
* it did it would lead to recursion). Also when running as a
* wayland compositor we shouldn't be assuming that we're running
* with the clutter x11 backend.
*/
if (klass->xevent_filter && klass->xevent_filter (plugin, xev))
return TRUE;
else if (!meta_is_wayland_compositor ())
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
else
return FALSE;
}
void
meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
{

View File

@@ -31,6 +31,7 @@
#include <meta/meta-shaped-texture.h>
#include <meta/util.h>
#include "clutter-utils.h"
#include "meta-texture-tower.h"
#include "meta-shaped-texture-private.h"
@@ -91,11 +92,10 @@ struct _MetaShapedTexturePrivate
CoglTexture *texture;
CoglTexture *mask_texture;
CoglPipeline *pipeline;
CoglPipeline *pipeline_unshaped;
cairo_region_t *clip_region;
cairo_region_t *input_shape_region;
cairo_region_t *opaque_region;
guint tex_width, tex_height;
@@ -145,9 +145,8 @@ meta_shaped_texture_dispose (GObject *object)
meta_texture_tower_free (priv->paint_tower);
priv->paint_tower = NULL;
g_clear_pointer (&priv->pipeline, cogl_object_unref);
g_clear_pointer (&priv->pipeline_unshaped, cogl_object_unref);
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
meta_shaped_texture_set_mask_texture (self, NULL);
meta_shaped_texture_set_clip_region (self, NULL);
@@ -155,6 +154,76 @@ meta_shaped_texture_dispose (GObject *object)
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
}
static CoglPipeline *
get_unmasked_pipeline (CoglContext *ctx)
{
return cogl_pipeline_new (ctx);
}
static CoglPipeline *
get_masked_pipeline (CoglContext *ctx)
{
static CoglPipeline *template = NULL;
if (G_UNLIKELY (template == NULL))
{
template = cogl_pipeline_new (ctx);
cogl_pipeline_set_layer_combine (template, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
return cogl_pipeline_copy (template);
}
static CoglPipeline *
get_unblended_pipeline (CoglContext *ctx)
{
static CoglPipeline *template = NULL;
if (G_UNLIKELY (template == NULL))
{
CoglColor color;
template = cogl_pipeline_new (ctx);
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
cogl_pipeline_set_blend (template,
"RGBA = ADD (SRC_COLOR, 0)",
NULL);
cogl_pipeline_set_color (template, &color);
}
return cogl_pipeline_copy (template);
}
static void
paint_clipped_rectangle (CoglFramebuffer *fb,
CoglPipeline *pipeline,
cairo_rectangle_int_t *rect,
ClutterActorBox *alloc)
{
float coords[8];
float x1, y1, x2, y2;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
coords[0] = rect->x / (alloc->x2 - alloc->x1);
coords[1] = rect->y / (alloc->y2 - alloc->y1);
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
coords[4] = coords[0];
coords[5] = coords[1];
coords[6] = coords[2];
coords[7] = coords[3];
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
x1, y1, x2, y2,
&coords[0], 8);
}
static void
set_cogl_texture (MetaShapedTexture *stex,
CoglTexture *cogl_tex)
@@ -169,13 +238,7 @@ set_cogl_texture (MetaShapedTexture *stex,
if (priv->texture)
cogl_object_unref (priv->texture);
priv->texture = cogl_tex;
if (priv->pipeline != NULL)
cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
if (priv->pipeline_unshaped != NULL)
cogl_pipeline_set_layer_texture (priv->pipeline_unshaped, 0, COGL_TEXTURE (cogl_tex));
priv->texture = cogl_object_ref (cogl_tex);
if (cogl_tex != NULL)
{
@@ -210,14 +273,15 @@ meta_shaped_texture_paint (ClutterActor *actor)
{
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
MetaShapedTexturePrivate *priv = stex->priv;
CoglTexture *paint_tex;
guint tex_width, tex_height;
guchar opacity;
CoglContext *ctx;
CoglFramebuffer *fb;
CoglPipeline *pipeline = NULL;
CoglTexture *paint_tex;
ClutterActorBox alloc;
static CoglPipeline *pipeline_template = NULL;
static CoglPipeline *pipeline_unshaped_template = NULL;
CoglPipeline *pipeline;
cairo_region_t *blended_region = NULL;
CoglPipelineFilter filter;
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
@@ -254,105 +318,144 @@ meta_shaped_texture_paint (ClutterActor *actor)
if (tex_width == 0 || tex_height == 0) /* no contents yet */
return;
/* Use nearest-pixel interpolation if the texture is unscaled. This
* improves performance, especially with software rendering.
*/
filter = COGL_PIPELINE_FILTER_LINEAR;
if (!clutter_actor_is_in_clone_paint (actor))
{
int x_origin, y_origin;
if (meta_actor_is_untransformed (actor,
&x_origin,
&y_origin))
filter = COGL_PIPELINE_FILTER_NEAREST;
}
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
fb = cogl_get_draw_framebuffer ();
opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box (actor, &alloc);
if (priv->opaque_region != NULL && opacity == 255)
{
CoglPipeline *opaque_pipeline;
cairo_region_t *region;
int n_rects;
int i;
if (priv->clip_region != NULL)
{
region = cairo_region_copy (priv->clip_region);
cairo_region_intersect (region, priv->opaque_region);
}
else
{
region = cairo_region_reference (priv->opaque_region);
}
if (cairo_region_is_empty (region))
goto paint_blended;
opaque_pipeline = get_unblended_pipeline (ctx);
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
n_rects = cairo_region_num_rectangles (region);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
}
cogl_object_unref (opaque_pipeline);
if (priv->clip_region != NULL)
{
blended_region = cairo_region_copy (priv->clip_region);
}
else
{
cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
blended_region = cairo_region_create_rectangle (&rect);
}
cairo_region_subtract (blended_region, priv->opaque_region);
paint_blended:
cairo_region_destroy (region);
}
if (blended_region == NULL && priv->clip_region != NULL)
blended_region = cairo_region_reference (priv->clip_region);
if (blended_region != NULL && cairo_region_is_empty (blended_region))
goto out;
if (priv->mask_texture == NULL)
{
/* Use a single-layer texture if we don't have a mask. */
if (priv->pipeline_unshaped == NULL)
{
if (G_UNLIKELY (pipeline_unshaped_template == NULL))
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
pipeline_unshaped_template = cogl_pipeline_new (ctx);
}
priv->pipeline_unshaped = cogl_pipeline_copy (pipeline_unshaped_template);
}
pipeline = priv->pipeline_unshaped;
pipeline = get_unmasked_pipeline (ctx);
}
else
{
if (priv->pipeline == NULL)
{
if (G_UNLIKELY (pipeline_template == NULL))
{
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
pipeline_template = cogl_pipeline_new (ctx);
cogl_pipeline_set_layer_combine (pipeline_template, 1,
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
}
priv->pipeline = cogl_pipeline_copy (pipeline_template);
}
pipeline = priv->pipeline;
pipeline = get_masked_pipeline (ctx);
cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
cogl_pipeline_set_layer_filters (pipeline, 1, filter, filter);
}
cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex);
cogl_pipeline_set_layer_filters (pipeline, 0, filter, filter);
{
CoglColor color;
guchar opacity = clutter_actor_get_paint_opacity (actor);
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_pipeline_set_color (pipeline, &color);
}
cogl_set_source (pipeline);
clutter_actor_get_allocation_box (actor, &alloc);
if (priv->clip_region)
if (blended_region != NULL)
{
int n_rects;
int i;
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
# define MAX_RECTS 16
n_rects = cairo_region_num_rectangles (priv->clip_region);
n_rects = cairo_region_num_rectangles (blended_region);
if (n_rects <= MAX_RECTS)
{
float coords[8];
float x1, y1, x2, y2;
int i;
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->clip_region, i, &rect);
cairo_region_get_rectangle (blended_region, i, &rect);
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
continue;
x1 = rect.x;
y1 = rect.y;
x2 = rect.x + rect.width;
y2 = rect.y + rect.height;
coords[0] = rect.x / (alloc.x2 - alloc.x1);
coords[1] = rect.y / (alloc.y2 - alloc.y1);
coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
coords[4] = coords[0];
coords[5] = coords[1];
coords[6] = coords[2];
coords[7] = coords[3];
cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
&coords[0], 8);
paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
}
return;
goto out;
}
}
cogl_rectangle (0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
cogl_framebuffer_draw_rectangle (fb, pipeline,
0, 0,
alloc.x2 - alloc.x1,
alloc.y2 - alloc.y1);
out:
if (pipeline != NULL)
cogl_object_unref (pipeline);
if (blended_region != NULL)
cairo_region_destroy (blended_region);
}
static void
@@ -368,13 +471,16 @@ meta_shaped_texture_pick (ClutterActor *actor,
/* If there is no region then use the regular pick */
if (priv->input_shape_region == NULL)
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
->pick (actor, color);
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color);
else
{
int n_rects;
float *rectangles;
int i;
CoglPipeline *pipeline;
CoglContext *ctx;
CoglFramebuffer *fb;
CoglColor cogl_color;
/* Note: We don't bother trying to intersect the pick and clip regions
* since needing to copy the region, do the intersection, and probably
@@ -403,12 +509,17 @@ meta_shaped_texture_pick (ClutterActor *actor,
rectangles[pos + 3] = rect.y + rect.height;
}
cogl_set_source_color4ub (color->red,
color->green,
color->blue,
color->alpha);
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
fb = cogl_get_draw_framebuffer ();
cogl_rectangles (rectangles, n_rects);
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color (pipeline, &cogl_color);
cogl_framebuffer_draw_rectangles (fb, pipeline,
rectangles, n_rects);
cogl_object_unref (pipeline);
}
}
@@ -601,19 +712,19 @@ wayland_surface_update_area (MetaShapedTexture *stex,
}
}
static void
queue_damage_redraw_with_clip (MetaShapedTexture *stex,
int x,
int y,
int width,
int height)
static gboolean
get_clip (MetaShapedTexture *stex,
int x,
int y,
int width,
int height,
cairo_rectangle_int_t *clip)
{
ClutterActor *self = CLUTTER_ACTOR (stex);
MetaShapedTexturePrivate *priv;
ClutterActorBox allocation;
float scale_x;
float scale_y;
cairo_rectangle_int_t clip;
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the actor's
* coordinate space so we need to convert from surface coordinates to
@@ -627,41 +738,60 @@ queue_damage_redraw_with_clip (MetaShapedTexture *stex,
* it here.
*/
if (!clutter_actor_has_allocation (self))
{
clutter_actor_queue_redraw (self);
return;
}
return FALSE;
priv = stex->priv;
if (priv->tex_width == 0 || priv->tex_height == 0)
return;
return FALSE;
clutter_actor_get_allocation_box (self, &allocation);
scale_x = (allocation.x2 - allocation.x1) / priv->tex_width;
scale_y = (allocation.y2 - allocation.y1) / priv->tex_height;
clip.x = x * scale_x;
clip.y = y * scale_y;
clip.width = width * scale_x;
clip.height = height * scale_y;
clutter_actor_queue_redraw_with_clip (self, &clip);
clip->x = x * scale_x;
clip->y = y * scale_y;
clip->width = width * scale_x;
clip->height = height * scale_y;
return TRUE;
}
void
/**
* meta_shaped_texture_update_area:
* @stex: #MetaShapedTexture
* @x: the x coordinate of the damaged area
* @y: the y coordinate of the damaged area
* @width: the width of the damaged area
* @height: the height of the damaged area
* @unobscured_region: The unobscured region of the window or %NULL if
* there is no valid one (like when the actor is transformed or
* has a mapped clone)
*
* Repairs the damaged area indicated by @x, @y, @width and @height
* and queues a redraw for the intersection @visibible_region and
* the damage area. If @visibible_region is %NULL a redraw will always
* get queued.
*
* Return value: Whether a redraw have been queued or not
*/
gboolean
meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height)
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region)
{
MetaShapedTexturePrivate *priv;
cairo_rectangle_int_t clip;
gboolean has_clip;
priv = stex->priv;
if (priv->texture == NULL)
return;
return FALSE;
switch (priv->type)
{
@@ -676,7 +806,40 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
queue_damage_redraw_with_clip (stex, x, y, width, height);
has_clip = get_clip (stex, x, y, width, height, &clip);
if (unobscured_region)
{
cairo_region_t *intersection;
if (cairo_region_is_empty (unobscured_region))
return FALSE;
intersection = cairo_region_copy (unobscured_region);
if (has_clip)
cairo_region_intersect_rectangle (intersection, &clip);
if (!cairo_region_is_empty (intersection))
{
cairo_rectangle_int_t damage_rect;
cairo_region_get_extents (intersection, &damage_rect);
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
cairo_region_destroy (intersection);
return TRUE;
}
cairo_region_destroy (intersection);
return FALSE;
}
if (has_clip)
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
else
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
return TRUE;
}
/**
@@ -733,26 +896,7 @@ meta_shaped_texture_attach_wayland_buffer (MetaShapedTexture *stex,
g_return_if_fail (priv->wayland.surface->buffer_ref.buffer == buffer);
if (buffer)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglError *catch_error = NULL;
CoglTexture *texture =
COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
buffer->resource,
&catch_error));
if (!texture)
{
cogl_error_free (catch_error);
}
else
{
buffer->width = cogl_texture_get_width (texture);
buffer->height = cogl_texture_get_height (texture);
}
set_cogl_texture (stex, texture);
}
set_cogl_texture (stex, buffer->texture);
else
set_cogl_texture (stex, NULL);
@@ -812,8 +956,8 @@ meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
/**
* meta_shaped_texture_set_clip_region:
* @stex: a #MetaShapedTexture
* @clip_region: (transfer full): the region of the texture that
* is visible and should be painted.
* @clip_region: the region of the texture that is visible and
* should be painted.
*
* Provides a hint to the texture about what areas of the texture
* are not completely obscured and thus need to be painted. This
@@ -834,10 +978,7 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
priv = stex->priv;
if (priv->clip_region)
{
cairo_region_destroy (priv->clip_region);
priv->clip_region = NULL;
}
cairo_region_destroy (priv->clip_region);
if (clip_region)
priv->clip_region = cairo_region_copy (clip_region);
@@ -845,6 +986,36 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
priv->clip_region = NULL;
}
/**
* meta_shaped_texture_set_opaque_region:
* @stex: a #MetaShapedTexture
* @opaque_region: (transfer full): the region of the texture that
* can have blending turned off.
*
* As most windows have a large portion that does not require blending,
* we can easily turn off blending if we know the areas that do not
* require blending. This sets the region where we will not blend for
* optimization purposes.
*/
void
meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
cairo_region_t *opaque_region)
{
MetaShapedTexturePrivate *priv;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
priv = stex->priv;
if (priv->opaque_region)
cairo_region_destroy (priv->opaque_region);
if (opaque_region)
priv->opaque_region = cairo_region_reference (opaque_region);
else
priv->opaque_region = NULL;
}
/**
* meta_shaped_texture_get_image:
* @stex: A #MetaShapedTexture

View File

@@ -70,11 +70,14 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
void meta_window_actor_set_visible_region (MetaWindowActor *self,
cairo_region_t *visible_region);
void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region);
void meta_window_actor_reset_visible_regions (MetaWindowActor *self);
void meta_window_actor_set_clip_region (MetaWindowActor *self,
cairo_region_t *clip_region);
void meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region);
void meta_window_actor_reset_clip_regions (MetaWindowActor *self);
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region);
void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event);

View File

@@ -10,7 +10,6 @@
#include <math.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h>
@@ -34,6 +33,7 @@
#include "meta-texture-rectangle.h"
#include "region-utils.h"
#include "meta-wayland-private.h"
#include "monitor-private.h"
enum {
POSITION_CHANGED,
@@ -71,13 +71,19 @@ struct _MetaWindowActorPrivate
/* A region that matches the shape of the window, including frame bounds */
cairo_region_t *shape_region;
/* If the window has an input shape, a region that matches the shape */
cairo_region_t *input_shape_region;
cairo_region_t *input_region;
/* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
* the shape region. */
cairo_region_t *opaque_region;
/* The region we should clip to when painting the shadow */
cairo_region_t *shadow_clip;
/* The region that is visible, used to optimize out redraws */
cairo_region_t *unobscured_region;
guint send_frame_messages_timer;
gint64 frame_drawn_time;
/* Extracted size-invariant shape used for shadows */
MetaWindowShape *shadow_shape;
@@ -187,6 +193,12 @@ static void meta_window_actor_handle_updates (MetaWindowActor *self);
static void check_needs_reshape (MetaWindowActor *self);
static void do_send_frame_drawn (MetaWindowActor *self, FrameData *frame);
static void do_send_frame_timings (MetaWindowActor *self,
FrameData *frame,
gint refresh_interval,
gint64 presentation_time);
G_DEFINE_TYPE (MetaWindowActor, meta_window_actor, CLUTTER_TYPE_ACTOR);
static void
@@ -357,16 +369,25 @@ meta_window_actor_constructed (GObject *object)
Window xwindow = priv->xwindow;
MetaWindow *window = priv->window;
Display *xdisplay = meta_display_get_xdisplay (display);
XRenderPictFormat *format;
if (!meta_is_wayland_compositor ())
priv->damage = XDamageCreate (xdisplay, xwindow,
XDamageReportBoundingBox);
format = XRenderFindVisualFormat (xdisplay, window->xvisual);
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
XRenderPictFormat *format;
if (format && format->type == PictTypeDirect && format->direct.alphaMask)
priv->argb32 = TRUE;
format = XRenderFindVisualFormat (xdisplay, window->xvisual);
if (format && format->type == PictTypeDirect && format->direct.alphaMask)
priv->argb32 = TRUE;
}
else
{
/* XXX: parse shm formats to determine argb32 */
priv->argb32 = TRUE;
}
if (!priv->actor)
{
@@ -407,8 +428,8 @@ meta_window_actor_constructed (GObject *object)
/* Start off with empty regions to maintain the invariant that
these regions are always set */
priv->shape_region = cairo_region_create();
priv->input_shape_region = cairo_region_create();
priv->shape_region = cairo_region_create ();
priv->input_region = cairo_region_create ();
}
static void
@@ -430,15 +451,17 @@ meta_window_actor_dispose (GObject *object)
info = meta_screen_get_compositor_data (screen);
if (!meta_is_wayland_compositor ())
{
display = meta_screen_get_display (screen);
xdisplay = meta_display_get_xdisplay (display);
meta_window_actor_detach_x11_pixmap (self);
meta_window_actor_detach_x11_pixmap (self);
if (priv->send_frame_messages_timer != 0)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
}
g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
g_clear_pointer (&priv->input_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
@@ -449,6 +472,9 @@ meta_window_actor_dispose (GObject *object)
if (!meta_is_wayland_compositor () && priv->damage != None)
{
display = meta_screen_get_display (screen);
xdisplay = meta_display_get_xdisplay (display);
meta_error_trap_push (display);
XDamageDestroy (xdisplay, priv->damage);
meta_error_trap_pop (display);
@@ -661,6 +687,16 @@ meta_window_actor_paint (ClutterActor *actor)
gboolean appears_focused = meta_window_appears_focused (priv->window);
MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
/* This window got damage when obscured; we set up a timer
* to send frame completion events, but since we're drawing
* the window now (for some other reason) cancel the timer
* and send the completion events normally */
if (priv->send_frame_messages_timer != 0)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
}
if (shadow != NULL)
{
MetaShadowParams params;
@@ -731,6 +767,13 @@ meta_window_actor_get_paint_volume (ClutterActor *actor,
gdk_rectangle_union (&bounds, &shadow_bounds, &bounds);
}
if (priv->unobscured_region && !clutter_actor_has_mapped_clones (actor))
{
cairo_rectangle_int_t unobscured_bounds;
cairo_region_get_extents (priv->unobscured_region, &unobscured_bounds);
gdk_rectangle_intersect (&bounds, &unobscured_bounds, &bounds);
}
origin.x = bounds.x;
origin.y = bounds.y;
origin.z = 0.0f;
@@ -923,11 +966,66 @@ meta_window_actor_freeze (MetaWindowActor *self)
self->priv->freeze_count++;
}
static
gboolean send_frame_messages_timeout (gpointer data)
{
MetaWindowActor *self = (MetaWindowActor *) data;
MetaWindowActorPrivate *priv = self->priv;
FrameData *frame = g_slice_new0 (FrameData);
frame->sync_request_serial = priv->window->sync_request_serial;
do_send_frame_drawn (self, frame);
do_send_frame_timings (self, frame, 0, 0);
priv->needs_frame_drawn = FALSE;
priv->send_frame_messages_timer = 0;
frame_data_free (frame);
return FALSE;
}
static void
queue_send_frame_messages_timeout (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
MetaWindow *window = priv->window;
MetaOutput *outputs;
guint n_outputs, i;
float refresh_rate = 60.0f;
gint interval, offset;
outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
for (i = 0; i < n_outputs; i++)
{
if (outputs[i].output_id == window->monitor->output_id && outputs[i].crtc)
{
refresh_rate = outputs[i].crtc->current_mode->refresh_rate;
break;
}
}
interval = (int)(1000000 / refresh_rate) * 6;
offset = MAX (0, priv->frame_drawn_time + interval - current_time) / 1000;
/* The clutter master clock source has already been added with META_PRIORITY_REDRAW,
* so the timer will run *after* the clutter frame handling, if a frame is ready
* to be drawn when the timer expires.
*/
priv->send_frame_messages_timer = g_timeout_add_full (META_PRIORITY_REDRAW, offset, send_frame_messages_timeout, self, NULL);
}
static void
meta_window_actor_damage_all (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
CoglTexture *texture;
gboolean redraw_queued;
if (!priv->needs_damage_all)
return;
@@ -937,13 +1035,16 @@ meta_window_actor_damage_all (MetaWindowActor *self)
if (!priv->mapped || priv->needs_pixmap)
return;
meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture));
redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture),
clutter_actor_has_mapped_clones (priv->actor) ?
NULL : priv->unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
priv->needs_damage_all = FALSE;
priv->repaint_scheduled = TRUE;
}
static void
@@ -999,14 +1100,31 @@ meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
if (!priv->repaint_scheduled)
{
gboolean is_obscured = FALSE;
/* Find out whether the window is completly obscured */
if (priv->unobscured_region)
{
cairo_region_t *unobscured_window_region;
unobscured_window_region = cairo_region_copy (priv->shape_region);
cairo_region_intersect (unobscured_window_region, priv->unobscured_region);
is_obscured = cairo_region_is_empty (unobscured_window_region);
cairo_region_destroy (unobscured_window_region);
}
/* A frame was marked by the client without actually doing any
* damage, or while we had the window frozen (e.g. during an
* interactive resize.) We need to make sure that the
* damage or any unobscured, or while we had the window frozen
* (e.g. during an interactive resize.) We need to make sure that the
* pre_paint/post_paint functions get called, enabling us to
* send a _NET_WM_FRAME_DRAWN. We do a 1-pixel redraw to get
* consistent timing with non-empty frames.
* consistent timing with non-empty frames. If the window
* is completely obscured we fire off the send_frame_messages timeout.
*/
if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
if (is_obscured)
{
queue_send_frame_messages_timeout (self);
}
else if (priv->mapped && (!meta_is_wayland_compositor () || !priv->needs_pixmap))
{
const cairo_rectangle_int_t clip = { 0, 0, 1, 1 };
clutter_actor_queue_redraw_with_clip (priv->actor, &clip);
@@ -1260,7 +1378,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
if (priv->opacity != 0xff)
return FALSE;
if (metaWindow->has_shape)
if (metaWindow->shape_region != NULL)
return FALSE;
if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
@@ -1324,6 +1442,12 @@ meta_window_actor_destroy (MetaWindowActor *self)
window_type = meta_window_get_window_type (window);
meta_window_set_compositor_private (window, NULL);
if (priv->send_frame_messages_timer != 0)
{
g_source_remove (priv->send_frame_messages_timer);
priv->send_frame_messages_timer = 0;
}
/*
* We remove the window from internal lookup hashes and thus any other
* unmap events etc fail
@@ -1359,6 +1483,22 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
MetaWindowActorPrivate *priv = self->priv;
MetaRectangle window_rect;
meta_window_get_input_rect (priv->window, &window_rect);
/* When running as a display server we catch size changes when new
buffers are attached */
if (!meta_is_wayland_compositor ())
{
if (priv->last_width != window_rect.width ||
priv->last_height != window_rect.height)
{
priv->x11_size_changed = TRUE;
priv->last_width = window_rect.width;
priv->last_height = window_rect.height;
}
}
/* Normally we want freezing a window to also freeze its position; this allows
* windows to atomically move and resize together, either under app control,
* or because the user is resizing from the left/top. But on initial placement
@@ -1369,22 +1509,12 @@ meta_window_actor_sync_actor_geometry (MetaWindowActor *self,
if (is_frozen (self) && !did_placement)
return;
meta_window_get_input_rect (priv->window, &window_rect);
/* When running as a display server then we instead catch size changes when
* new buffers are attached */
if (!meta_is_wayland_compositor ())
{
if (priv->last_width != window_rect.width ||
priv->last_height != window_rect.height)
if (priv->x11_size_changed)
{
priv->x11_size_changed = TRUE;
meta_window_actor_queue_create_x11_pixmap (self);
meta_window_actor_update_shape (self);
priv->last_width = window_rect.width;
priv->last_height = window_rect.height;
}
}
@@ -1726,40 +1856,67 @@ see_region (cairo_region_t *region,
#endif
/**
* meta_window_actor_set_visible_region:
* meta_window_actor_set_unobscured_region:
* @self: a #MetaWindowActor
* @visible_region: the region of the screen that isn't completely
* @unobscured_region: the region of the screen that isn't completely
* obscured.
*
* Provides a hint as to what areas of the window need to queue
* redraws when damaged. Regions not in @unobscured_region are completely obscured.
* Unlike meta_window_actor_set_clip_region(), the region here
* doesn't take into account any clipping that is in effect while drawing.
*/
void
meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->unobscured_region)
cairo_region_destroy (priv->unobscured_region);
if (unobscured_region)
priv->unobscured_region = cairo_region_copy (unobscured_region);
else
priv->unobscured_region = NULL;
}
/**
* meta_window_actor_set_clip_region:
* @self: a #MetaWindowActor
* @clip_region: the region of the screen that isn't completely
* obscured.
*
* Provides a hint as to what areas of the window need to be
* drawn. Regions not in @visible_region are completely obscured.
* drawn. Regions not in @clip_region are completely obscured or
* not drawn in this frame.
* This will be set before painting then unset afterwards.
*/
void
meta_window_actor_set_visible_region (MetaWindowActor *self,
cairo_region_t *visible_region)
meta_window_actor_set_clip_region (MetaWindowActor *self,
cairo_region_t *clip_region)
{
MetaWindowActorPrivate *priv = self->priv;
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
visible_region);
clip_region);
}
/**
* meta_window_actor_set_visible_region_beneath:
* meta_window_actor_set_clip_region_beneath:
* @self: a #MetaWindowActor
* @visible_region: the region of the screen that isn't completely
* @clip_region: the region of the screen that isn't completely
* obscured beneath the main window texture.
*
* Provides a hint as to what areas need to be drawn *beneath*
* the main window texture. This is the relevant visible region
* the main window texture. This is the relevant clip region
* when drawing the shadow, properly accounting for areas of the
* shadow hid by the window itself. This will be set before painting
* then unset afterwards.
*/
void
meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region)
meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region)
{
MetaWindowActorPrivate *priv = self->priv;
gboolean appears_focused = meta_window_appears_focused (priv->window);
@@ -1778,14 +1935,14 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
}
/**
* meta_window_actor_reset_visible_regions:
* meta_window_actor_reset_clip_regions:
* @self: a #MetaWindowActor
*
* Unsets the regions set by meta_window_actor_set_visible_region() and
* meta_window_actor_set_visible_region_beneath()
* Unsets the regions set by meta_window_actor_set_clip_region() and
* meta_window_actor_set_clip_region_beneath()
*/
void
meta_window_actor_reset_visible_regions (MetaWindowActor *self)
meta_window_actor_reset_clip_regions (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
@@ -1960,6 +2117,7 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
{
MetaWindowActorPrivate *priv = self->priv;
MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
gboolean redraw_queued;
priv->received_x11_damage = TRUE;
@@ -2007,12 +2165,16 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
if (!priv->mapped || priv->needs_pixmap)
return;
meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
event->area.x,
event->area.y,
event->area.width,
event->area.height);
priv->repaint_scheduled = TRUE;
redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
event->area.x,
event->area.y,
event->area.width,
event->area.height,
clutter_actor_has_mapped_clones (priv->actor) ?
NULL : priv->unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
}
void
@@ -2023,13 +2185,17 @@ meta_window_actor_process_wayland_damage (MetaWindowActor *self,
int height)
{
MetaWindowActorPrivate *priv = self->priv;
gboolean redraw_queued;
if (!priv->mapped)
return;
meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
x, y, width, height);
priv->repaint_scheduled = TRUE;
redraw_queued = meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
x, y, width, height,
clutter_actor_has_mapped_clones (priv->actor) ?
NULL : priv->unobscured_region);
priv->repaint_scheduled = priv->repaint_scheduled || redraw_queued;
}
void
@@ -2171,85 +2337,21 @@ build_and_scan_frame_mask (MetaWindowActor *self,
g_free (mask_data);
}
static cairo_region_t *
region_create_from_x_rectangles (const XRectangle *rects,
int n_rects,
int dx,
int dy)
{
int i;
cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i ++)
{
cairo_rects[i].x = rects[i].x + dx;
cairo_rects[i].y = rects[i].y + dy;
cairo_rects[i].width = rects[i].width;
cairo_rects[i].height = rects[i].height;
}
return cairo_region_create_rectangles (cairo_rects, n_rects);
}
static void
meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
meta_window_actor_update_shape_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *region = NULL;
gboolean needs_mask;
if (priv->shadow_shape != NULL)
if (priv->window->frame != NULL && priv->window->shape_region != NULL)
{
meta_window_shape_unref (priv->shadow_shape);
priv->shadow_shape = NULL;
region = cairo_region_copy (priv->window->shape_region);
cairo_region_translate (region, client_area->x, client_area->y);
}
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
#ifdef HAVE_SHAPE
if (priv->window->has_shape)
else if (priv->window->shape_region != NULL)
{
/* Translate the set of XShape rectangles that we
* get from the X server to a cairo_region. */
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects;
int n_rects, ordering;
meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay,
priv->window->xwindow,
ShapeBounding,
&n_rects,
&ordering);
meta_error_trap_pop (display);
if (rects)
{
region = region_create_from_x_rectangles (rects, n_rects,
client_area->x,
client_area->y);
XFree (rects);
}
}
#endif
needs_mask = (region != NULL) || (priv->window->frame != NULL);
if (region != NULL)
{
/* The shape we get back from the client may have coordinates
* outside of the frame. The X SHAPE Extension requires that
* the overall shape the client provides never exceeds the
* "bounding rectangle" of the window -- the shape that the
* window would have gotten if it was unshaped. In our case,
* this is simply the client area.
*/
cairo_region_intersect_rectangle (region, client_area);
region = cairo_region_reference (priv->window->shape_region);
}
else
{
@@ -2259,11 +2361,67 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
region = cairo_region_create_rectangle (client_area);
}
/* The region at this point should be constrained to the
* bounds of the client rectangle. */
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL))
build_and_scan_frame_mask (self, client_area, region);
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
priv->shape_region = region;
g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref);
meta_window_actor_invalidate_shadow (self);
}
static void
meta_window_actor_update_input_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
cairo_region_t *region = NULL;
if (priv->window->frame != NULL && priv->window->input_region != NULL)
{
region = meta_frame_get_frame_bounds (priv->window->frame);
cairo_region_subtract_rectangle (region, client_area);
/* input_region is in client window coordinates, so translate the
* input region into that coordinate system and back */
cairo_region_translate (region, -client_area->x, -client_area->y);
cairo_region_union (region, priv->window->input_region);
cairo_region_translate (region, client_area->x, client_area->y);
}
else if (priv->window->shape_region != NULL)
{
region = cairo_region_reference (priv->window->input_region);
}
else
{
/* If we don't have a shape on the server, that means that
* we have an implicit shape of one rectangle covering the
* entire window. */
region = cairo_region_create_rectangle (client_area);
}
meta_shaped_texture_set_input_shape_region (stex, region);
cairo_region_destroy (region);
}
static void
meta_window_actor_update_opaque_region (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
if (priv->argb32 && priv->window->opaque_region != NULL)
{
MetaFrameBorders borders;
meta_frame_calc_borders (priv->window->frame, &borders);
/* The opaque region is defined to be a part of the
* window which ARGB32 will always paint with opaque
* pixels. For these regions, we want to avoid painting
@@ -2275,91 +2433,16 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
* case, graphical glitches will occur.
*/
priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
cairo_region_translate (priv->opaque_region, client_area->x, client_area->y);
cairo_region_intersect (priv->opaque_region, region);
cairo_region_translate (priv->opaque_region, borders.total.left, borders.total.top);
cairo_region_intersect (priv->opaque_region, priv->shape_region);
}
else if (priv->argb32)
priv->opaque_region = NULL;
else
priv->opaque_region = cairo_region_reference (region);
priv->opaque_region = cairo_region_reference (priv->shape_region);
if (needs_mask)
{
/* This takes the region, generates a mask using GTK+
* and scans the mask looking for all opaque pixels,
* adding it to region.
*/
build_and_scan_frame_mask (self, client_area, region);
}
priv->shape_region = region;
meta_window_actor_invalidate_shadow (self);
}
static void
meta_window_actor_update_x11_input_shape_region (MetaWindowActor *self,
cairo_rectangle_int_t *client_area)
{
MetaWindowActorPrivate *priv = self->priv;
cairo_region_t *region = NULL;
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
#ifdef HAVE_SHAPE
/* Note: we currently assume that mutter never sets an input region
* when there is a frame. */
if (priv->window->frame == NULL && priv->window->has_input_shape)
{
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XRectangle *rects;
int n_rects, ordering;
/* Note we only actually query the ShapeInput shape of a window
* when we don't have a frame because we assume currently that
* mutter never sets an ShapeInput shape on a frame. */
meta_error_trap_push (display);
rects = XShapeGetRectangles (xdisplay,
priv->window->xwindow,
ShapeInput,
&n_rects,
&ordering);
meta_error_trap_pop (display);
if (rects)
{
region = region_create_from_x_rectangles (rects, n_rects,
client_area->x,
client_area->y);
XFree (rects);
}
}
#endif /* HAVE_SHAPE */
if (region != NULL)
{
/* The X shape extension requires us to intersect the input
* region with the effective bounding shape to determine the
* effective input region.
*/
if (priv->shape_region)
cairo_region_intersect (region, priv->shape_region);
else
cairo_region_intersect_rectangle (region, client_area);
}
else
{
/* If we don't have a shape on the server, that means that we
* have an implicit shape of one rectangle covering the entire
* window. */
region = cairo_region_create_rectangle (client_area);
}
priv->input_shape_region = region;
meta_shaped_texture_set_input_shape_region (META_SHAPED_TEXTURE (priv->actor),
priv->input_shape_region);
meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor),
priv->opaque_region);
}
static void
@@ -2385,24 +2468,9 @@ check_needs_reshape (MetaWindowActor *self)
else
client_area.height = priv->window->rect.height;
if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
{
meta_window_actor_update_x11_shape_region (self, &client_area);
meta_window_actor_update_x11_input_shape_region (self, &client_area);
}
else
{
/* TODO: properly support setting an input region as specified
* via the wayland protocol */
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
priv->shape_region = cairo_region_create_rectangle (&client_area);
priv->opaque_region = cairo_region_reference (priv->shape_region);
priv->input_shape_region = cairo_region_reference (priv->shape_region);
}
meta_window_actor_update_shape_region (self, &client_area);
meta_window_actor_update_input_region (self, &client_area);
meta_window_actor_update_opaque_region (self);
priv->needs_reshape = FALSE;
}
@@ -2560,6 +2628,35 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
}
}
static void
do_send_frame_drawn (MetaWindowActor *self, FrameData *frame)
{
MetaWindowActorPrivate *priv = self->priv;
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XClientMessageEvent ev = { 0, };
frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display,
g_get_monotonic_time ());
priv->frame_drawn_time = frame->frame_drawn_time;
ev.type = ClientMessage;
ev.window = meta_window_get_xwindow (priv->window);
ev.message_type = display->atom__NET_WM_FRAME_DRAWN;
ev.format = 32;
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[1] = frame->sync_request_serial >> 32;
ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[3] = frame->frame_drawn_time >> 32;
meta_error_trap_push (display);
XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
XFlush (xdisplay);
meta_error_trap_pop (display);
}
void
meta_window_actor_post_paint (MetaWindowActor *self)
{
@@ -2567,47 +2664,29 @@ meta_window_actor_post_paint (MetaWindowActor *self)
priv->repaint_scheduled = FALSE;
/* This window had damage, but wasn't actually redrawn because
* it is obscured. So we should wait until timer expiration
* before sending _NET_WM_FRAME_* messages.
*/
if (priv->send_frame_messages_timer != 0)
return;
if (priv->needs_frame_drawn)
{
MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
XClientMessageEvent ev = { 0, };
FrameData *frame = priv->frames->data;
frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display,
g_get_monotonic_time ());
ev.type = ClientMessage;
ev.window = meta_window_get_xwindow (priv->window);
ev.message_type = display->atom__NET_WM_FRAME_DRAWN;
ev.format = 32;
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[1] = frame->sync_request_serial >> 32;
ev.data.l[2] = frame->frame_drawn_time & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[3] = frame->frame_drawn_time >> 32;
meta_error_trap_push (display);
XSendEvent (xdisplay, ev.window, False, 0, (XEvent*) &ev);
XFlush (xdisplay);
meta_error_trap_pop (display);
do_send_frame_drawn (self, priv->frames->data);
priv->needs_frame_drawn = FALSE;
}
}
static void
send_frame_timings (MetaWindowActor *self,
FrameData *frame,
CoglFrameInfo *frame_info,
gint64 presentation_time)
do_send_frame_timings (MetaWindowActor *self,
FrameData *frame,
gint refresh_interval,
gint64 presentation_time)
{
MetaWindowActorPrivate *priv = self->priv;
MetaDisplay *display = meta_screen_get_display (priv->screen);
Display *xdisplay = meta_display_get_xdisplay (display);
float refresh_rate;
int refresh_interval;
XClientMessageEvent ev = { 0, };
@@ -2618,13 +2697,6 @@ send_frame_timings (MetaWindowActor *self,
ev.data.l[0] = frame->sync_request_serial & G_GUINT64_CONSTANT(0xffffffff);
ev.data.l[1] = frame->sync_request_serial >> 32;
refresh_rate = cogl_frame_info_get_refresh_rate (frame_info);
/* 0.0 is a flag for not known, but sanity-check against other odd numbers */
if (refresh_rate >= 1.0)
refresh_interval = (int) (0.5 + 1000000 / refresh_rate);
else
refresh_interval = 0;
if (presentation_time != 0)
{
gint64 presentation_time_server = meta_compositor_monotonic_time_to_server_time (display,
@@ -2646,6 +2718,25 @@ send_frame_timings (MetaWindowActor *self,
meta_error_trap_pop (display);
}
static void
send_frame_timings (MetaWindowActor *self,
FrameData *frame,
CoglFrameInfo *frame_info,
gint64 presentation_time)
{
float refresh_rate;
int refresh_interval;
refresh_rate = cogl_frame_info_get_refresh_rate (frame_info);
/* 0.0 is a flag for not known, but sanity-check against other odd numbers */
if (refresh_rate >= 1.0)
refresh_interval = (int) (0.5 + 1000000 / refresh_rate);
else
refresh_interval = 0;
do_send_frame_timings (self, frame, refresh_interval, presentation_time);
}
void
meta_window_actor_frame_complete (MetaWindowActor *self,
CoglFrameInfo *frame_info,

View File

@@ -90,17 +90,30 @@ painting_untransformed (MetaWindowGroup *window_group,
static void
meta_window_group_paint (ClutterActor *actor)
{
cairo_region_t *visible_region;
ClutterActor *stage;
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
ClutterActorIter iter;
ClutterActor *child;
cairo_rectangle_int_t visible_rect;
cairo_rectangle_int_t visible_rect, clip_rect;
int paint_x_origin, paint_y_origin;
int actor_x_origin, actor_y_origin;
int paint_x_offset, paint_y_offset;
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
MetaCompScreen *info;
MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
ClutterActor *stage = clutter_actor_get_stage (actor);
/* Start off by treating all windows as completely unobscured, so damage anywhere
* in a window queues redraws, but confine it more below. */
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
meta_window_actor_set_unobscured_region (window_actor, NULL);
}
}
/* Normally we expect an actor to be drawn at it's position on the screen.
* However, if we're inside the paint of a ClutterClone, that won't be the
@@ -125,17 +138,22 @@ meta_window_group_paint (ClutterActor *actor)
paint_x_offset = paint_x_origin - actor_x_origin;
paint_y_offset = paint_y_origin - actor_y_origin;
visible_rect.x = visible_rect.y = 0;
visible_rect.width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
visible_rect.height = clutter_actor_get_height (CLUTTER_ACTOR (stage));
unobscured_region = cairo_region_create_rectangle (&visible_rect);
/* Get the clipped redraw bounds from Clutter so that we can avoid
* painting shadows on windows that don't need to be painted in this
* frame. In the case of a multihead setup with mismatched monitor
* sizes, we could intersect this with an accurate union of the
* monitors to avoid painting shadows that are visible only in the
* holes. */
stage = clutter_actor_get_stage (actor);
clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
&visible_rect);
&clip_rect);
visible_region = cairo_region_create_rectangle (&visible_rect);
clip_region = cairo_region_create_rectangle (&clip_rect);
if (!meta_is_wayland_compositor ())
{
@@ -146,7 +164,8 @@ meta_window_group_paint (ClutterActor *actor)
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
}
}
@@ -186,7 +205,6 @@ meta_window_group_paint (ClutterActor *actor)
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindow *meta_window;
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
int x, y;
@@ -196,27 +214,28 @@ meta_window_group_paint (ClutterActor *actor)
x += paint_x_offset;
y += paint_y_offset;
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (visible_region, - x, - y);
cairo_region_translate (unobscured_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
meta_window_actor_set_visible_region (window_actor, visible_region);
meta_window_actor_set_unobscured_region (window_actor, unobscured_region);
meta_window_actor_set_clip_region (window_actor, clip_region);
/* TODO: Track the opaque regions of wayland clients.
* Although wayland clients can report opaque window
* regions, for now we assume that all wayland clients are
* transparent... */
meta_window = meta_window_actor_get_meta_window (window_actor);
if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
{
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
if (obscured_region)
cairo_region_subtract (visible_region, obscured_region);
{
cairo_region_subtract (unobscured_region, obscured_region);
cairo_region_subtract (clip_region, obscured_region);
}
}
meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
cairo_region_translate (visible_region, x, y);
meta_window_actor_set_clip_region_beneath (window_actor, clip_region);
cairo_region_translate (unobscured_region, x, y);
cairo_region_translate (clip_region, x, y);
}
else if (META_IS_BACKGROUND_ACTOR (child) ||
META_IS_BACKGROUND_GROUP (child))
@@ -229,17 +248,18 @@ meta_window_group_paint (ClutterActor *actor)
x += paint_x_offset;
y += paint_y_offset;
cairo_region_translate (visible_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
if (META_IS_BACKGROUND_GROUP (child))
meta_background_group_set_visible_region (META_BACKGROUND_GROUP (child), visible_region);
meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), clip_region);
else
meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (child), visible_region);
cairo_region_translate (visible_region, x, y);
meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (child), clip_region);
cairo_region_translate (clip_region, x, y);
}
}
cairo_region_destroy (visible_region);
cairo_region_destroy (unobscured_region);
cairo_region_destroy (clip_region);
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
@@ -252,12 +272,12 @@ meta_window_group_paint (ClutterActor *actor)
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
meta_window_actor_reset_visible_regions (window_actor);
meta_window_actor_reset_clip_regions (window_actor);
}
else if (META_IS_BACKGROUND_ACTOR (child))
{
MetaBackgroundActor *background_actor = META_BACKGROUND_ACTOR (child);
meta_background_actor_set_visible_region (background_actor, NULL);
meta_background_actor_set_clip_region (background_actor, NULL);
}
}
}

View File

@@ -21,15 +21,14 @@
* 02111-1307, USA.
*/
#include <config.h>
#include <meta/meta-plugin.h>
#include <meta/window.h>
#include <meta/util.h>
#include <meta/meta-background-group.h>
#include <meta/meta-background-actor.h>
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x
#include <meta/util.h>
#include <glib/gi18n-lib.h>
#include <clutter/clutter.h>
#include <gmodule.h>

View File

@@ -53,6 +53,7 @@
#include "bell.h"
#include "screen-private.h"
#include "window-private.h"
#include "util-private.h"
#include <meta/prefs.h>
#include <meta/compositor.h>
#ifdef HAVE_LIBCANBERRA

View File

@@ -447,12 +447,14 @@ setup_constraint_info (ConstraintInfo *info,
/* Workaround braindead legacy apps that don't know how to
* fullscreen themselves properly - don't get fooled by
* windows which hide their titlebar when maximized; that's
* not the same as fullscreen, even if there are no struts
* making the workarea smaller than the monitor.
* windows which hide their titlebar when maximized or which are
* client decorated; that's not the same as fullscreen, even
* if there are no struts making the workarea smaller than
* the monitor.
*/
if (meta_prefs_get_force_fullscreen() &&
!window->hide_titlebar_when_maximized &&
window->decorated &&
meta_rectangle_equal (new, &monitor_info->rect) &&
window->has_fullscreen_func &&
!window->fullscreen)

View File

@@ -35,7 +35,8 @@ typedef enum
META_DO_GRAVITY_ADJUST = 1 << 1,
META_IS_USER_ACTION = 1 << 2,
META_IS_MOVE_ACTION = 1 << 3,
META_IS_RESIZE_ACTION = 1 << 4
META_IS_RESIZE_ACTION = 1 << 4,
META_IS_WAYLAND_RESIZE = 1 << 5
} MetaMoveResizeFlags;
void meta_window_constrain (MetaWindow *window,

View File

@@ -29,6 +29,7 @@
#include "workspace-private.h"
#include <meta/prefs.h>
#include <meta/errors.h>
#include "util-private.h"
/* Looks up the MetaWindow representing the frame of the given X window.
* Used as a helper function by a bunch of the functions below.
@@ -89,7 +90,7 @@ meta_core_get (Display *xdisplay,
if (request != META_CORE_WINDOW_HAS_FRAME &&
(window == NULL || window->frame == NULL)) {
meta_bug ("No such frame window 0x%lx!\n", xwindow);
return;
goto out;
}
while (request != META_CORE_GET_END) {
@@ -99,7 +100,7 @@ meta_core_get (Display *xdisplay,
switch (request) {
case META_CORE_WINDOW_HAS_FRAME:
*((gboolean*)answer) = window != NULL && window->frame != NULL;
if (!*((gboolean*)answer)) return; /* see above */
if (!*((gboolean*)answer)) goto out; /* see above */
break;
case META_CORE_GET_CLIENT_WIDTH:
*((gint*)answer) = window->rect.width;
@@ -154,12 +155,13 @@ meta_core_get (Display *xdisplay,
break;
default:
meta_warning(_("Unknown window information request: %d"), request);
meta_warning("Unknown window information request: %d\n", request);
}
request = va_arg (args, MetaCoreGetType);
}
out:
va_end (args);
}

View File

@@ -25,7 +25,7 @@
#define _XOPEN_SOURCE /* for kill() */
#include <config.h>
#include <meta/util.h>
#include "util-private.h"
#include "window-private.h"
#include <meta/errors.h>
#include <meta/workspace.h>

View File

@@ -154,6 +154,7 @@ struct _MetaDisplay
GSList *screens;
MetaScreen *active_screen;
GHashTable *xids;
GHashTable *wayland_windows;
int error_traps;
int (* error_trap_handler) (Display *display,
XErrorEvent *error);
@@ -380,6 +381,11 @@ void meta_display_register_x_window (MetaDisplay *display,
void meta_display_unregister_x_window (MetaDisplay *display,
Window xwindow);
void meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_unregister_wayland_window (MetaDisplay *display,
MetaWindow *window);
#ifdef HAVE_XSYNC
MetaWindow* meta_display_lookup_sync_alarm (MetaDisplay *display,
XSyncAlarm alarm);

View File

@@ -34,7 +34,7 @@
#include <config.h>
#include "display-private.h"
#include <meta/util.h>
#include "util-private.h"
#include <meta/main.h>
#include "screen-private.h"
#include "window-private.h"
@@ -51,7 +51,6 @@
#include <meta/compositor.h>
#include <meta/compositor-mutter.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include "mutter-enum-types.h"
#include "meta-idle-monitor-private.h"
@@ -64,9 +63,7 @@
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
#ifdef HAVE_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
@@ -421,7 +418,7 @@ enable_compositor (MetaDisplay *display)
!META_DISPLAY_HAS_DAMAGE (display) ||
!META_DISPLAY_HAS_RENDER (display))
{
meta_warning (_("Missing %s extension required for compositing"),
meta_warning ("Missing %s extension required for compositing",
!META_DISPLAY_HAS_COMPOSITE (display) ? "composite" :
!META_DISPLAY_HAS_DAMAGE (display) ? "damage" : "render");
return;
@@ -609,6 +606,7 @@ meta_display_open (void)
the_display->xids = g_hash_table_new (meta_unsigned_long_hash,
meta_unsigned_long_equal);
the_display->wayland_windows = g_hash_table_new (NULL, NULL);
i = 0;
while (i < N_IGNORED_CROSSING_SERIALS)
@@ -828,14 +826,10 @@ meta_display_open (void)
meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer\n");
}
#ifdef HAVE_XCURSOR
{
XcursorSetTheme (the_display->xdisplay, meta_prefs_get_cursor_theme ());
XcursorSetDefaultSize (the_display->xdisplay, meta_prefs_get_cursor_size ());
}
#else /* HAVE_XCURSOR */
meta_verbose ("Not compiled with Xcursor support\n");
#endif /* !HAVE_XCURSOR */
/* Create the leader window here. Set its properties and
* use the timestamp from one of the PropertyNotify events
@@ -1054,6 +1048,19 @@ meta_display_list_windows (MetaDisplay *display,
winlist = g_slist_prepend (winlist, window);
}
g_hash_table_iter_init (&iter, display->wayland_windows);
while (g_hash_table_iter_next (&iter, &key, &value))
{
MetaWindow *window = value;
if (!META_IS_WINDOW (window))
continue;
if (!window->override_redirect ||
(flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0)
winlist = g_slist_prepend (winlist, window);
}
/* Uniquify the list, since both frame windows and plain
* windows are in the hash
*/
@@ -1876,14 +1883,17 @@ get_input_event (MetaDisplay *display,
case XI_ButtonRelease:
if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
return input_event;
break;
case XI_KeyPress:
case XI_KeyRelease:
if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID)
return input_event;
break;
case XI_FocusIn:
case XI_FocusOut:
if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID)
return input_event;
break;
case XI_Enter:
case XI_Leave:
if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
@@ -2336,59 +2346,9 @@ meta_display_handle_event (MetaDisplay *display,
XShapeEvent *sev = (XShapeEvent*) event;
if (sev->kind == ShapeBounding)
{
if (sev->shaped && !window->has_shape)
{
window->has_shape = TRUE;
meta_topic (META_DEBUG_SHAPES,
"Window %s now has a shape\n",
window->desc);
}
else if (!sev->shaped && window->has_shape)
{
window->has_shape = FALSE;
meta_topic (META_DEBUG_SHAPES,
"Window %s no longer has a shape\n",
window->desc);
}
else
{
meta_topic (META_DEBUG_SHAPES,
"Window %s shape changed\n",
window->desc);
}
if (display->compositor)
meta_compositor_window_x11_shape_changed (display->compositor,
window);
}
meta_window_update_shape_region_x11 (window);
else if (sev->kind == ShapeInput)
{
if (sev->shaped && !window->has_input_shape)
{
window->has_input_shape = TRUE;
meta_topic (META_DEBUG_SHAPES,
"Window %s now has an input shape\n",
window->desc);
}
else if (!sev->shaped && window->has_input_shape)
{
window->has_input_shape = FALSE;
meta_topic (META_DEBUG_SHAPES,
"Window %s no longer has an input shape\n",
window->desc);
}
else
{
meta_topic (META_DEBUG_SHAPES,
"Window %s input shape changed\n",
window->desc);
}
if (display->compositor)
meta_compositor_window_x11_shape_changed (display->compositor,
window);
}
meta_window_update_input_region_x11 (window);
}
else
{
@@ -3917,6 +3877,20 @@ meta_display_unregister_x_window (MetaDisplay *display,
remove_pending_pings_for_window (display, xwindow);
}
void
meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window)
{
g_hash_table_add (display->wayland_windows, window);
}
void
meta_display_unregister_wayland_window (MetaDisplay *display,
MetaWindow *window)
{
g_hash_table_remove (display->wayland_windows, window);
}
#ifdef HAVE_XSYNC
/* We store sync alarms in the window ID hash table, because they are
* just more types of XIDs in the same global space, but we have
@@ -3984,60 +3958,6 @@ meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display,
return is_a_no_focus_window;
}
Cursor
meta_display_create_x_cursor (MetaDisplay *display,
MetaCursor cursor)
{
Cursor xcursor;
guint glyph;
switch (cursor)
{
case META_CURSOR_DEFAULT:
glyph = XC_left_ptr;
break;
case META_CURSOR_NORTH_RESIZE:
glyph = XC_top_side;
break;
case META_CURSOR_SOUTH_RESIZE:
glyph = XC_bottom_side;
break;
case META_CURSOR_WEST_RESIZE:
glyph = XC_left_side;
break;
case META_CURSOR_EAST_RESIZE:
glyph = XC_right_side;
break;
case META_CURSOR_SE_RESIZE:
glyph = XC_bottom_right_corner;
break;
case META_CURSOR_SW_RESIZE:
glyph = XC_bottom_left_corner;
break;
case META_CURSOR_NE_RESIZE:
glyph = XC_top_right_corner;
break;
case META_CURSOR_NW_RESIZE:
glyph = XC_top_left_corner;
break;
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
glyph = XC_fleur;
break;
case META_CURSOR_BUSY:
glyph = XC_watch;
break;
default:
g_assert_not_reached ();
glyph = 0; /* silence compiler */
break;
}
xcursor = XCreateFontCursor (display->xdisplay, glyph);
return xcursor;
}
static Cursor
xcursor_for_op (MetaDisplay *display,
MetaGrabOp op)
@@ -4748,7 +4668,6 @@ void
meta_display_set_cursor_theme (const char *theme,
int size)
{
#ifdef HAVE_XCURSOR
GSList *tmp;
MetaDisplay *display = meta_get_display ();
@@ -4765,8 +4684,6 @@ meta_display_set_cursor_theme (const char *theme,
tmp = tmp->next;
}
#endif
}
/*
@@ -6034,7 +5951,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display)
gboolean
meta_display_supports_extended_barriers (MetaDisplay *display)
{
return META_DISPLAY_HAS_XINPUT_23 (display);
return META_DISPLAY_HAS_XINPUT_23 (display) && !meta_is_wayland_compositor ();
}
/**

View File

@@ -42,7 +42,7 @@
#include "frame.h"
#include "place.h"
#include <meta/prefs.h>
#include <meta/util.h>
#include "util-private.h"
#include <X11/keysym.h>
#include <string.h>
@@ -53,8 +53,13 @@
#include <X11/XKBlib.h>
#endif
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
#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,
@@ -1133,7 +1138,7 @@ meta_change_keygrab (MetaDisplay *display,
if (grab && result != Success)
{
if (result == BadAccess)
meta_warning (_("Some other program is already using the key %s with modifiers %x as a binding\n"), keysym_name (keysym), modmask | ignored_mask);
meta_warning ("Some other program is already using the key %s with modifiers %x as a binding\n", keysym_name (keysym), modmask | ignored_mask);
else
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to grab key %s with modifiers %x\n",
@@ -1330,7 +1335,7 @@ meta_display_grab_accelerator (MetaDisplay *display,
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to parse accelerator\n");
meta_warning (_("\"%s\" is not a valid accelerator\n"), accelerator);
meta_warning ("\"%s\" is not a valid accelerator\n", accelerator);
return META_KEYBINDING_ACTION_NONE;
}
@@ -4098,6 +4103,40 @@ handle_set_spew_mark (MetaDisplay *display,
meta_verbose ("-- MARK MARK MARK MARK --\n");
}
#ifdef HAVE_WAYLAND
static void
handle_switch_vt (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XIDeviceEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
{
gint vt = binding->handler->data;
MetaWaylandCompositor *compositor;
MetaLauncher *launcher;
compositor = meta_wayland_compositor_get_default ();
launcher = meta_wayland_compositor_get_launcher (compositor);
if (launcher)
{
GError *error;
error = NULL;
if (!meta_launcher_activate_vt (launcher, vt, &error))
{
g_warning ("Failed to switch VT: %s", error->message);
g_error_free (error);
}
}
else
{
g_debug ("Ignoring VT switch keybinding, not running as VT manager");
}
}
#endif
/**
* meta_keybindings_set_custom_handler:
* @name: The name of the keybinding to set
@@ -4161,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",
@@ -4422,6 +4462,60 @@ init_builtin_key_bindings (MetaDisplay *display)
META_KEYBINDING_ACTION_SET_SPEW_MARK,
handle_set_spew_mark, 0);
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
add_builtin_keybinding (display,
"switch-to-session-1",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 1);
add_builtin_keybinding (display,
"switch-to-session-2",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 2);
add_builtin_keybinding (display,
"switch-to-session-3",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 3);
add_builtin_keybinding (display,
"switch-to-session-4",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 4);
add_builtin_keybinding (display,
"switch-to-session-5",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 5);
add_builtin_keybinding (display,
"switch-to-session-6",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 6);
add_builtin_keybinding (display,
"switch-to-session-7",
mutter_wayland_keybindings,
META_KEY_BINDING_NONE,
META_KEYBINDING_ACTION_NONE,
handle_switch_vt, 7);
}
#endif
#undef REVERSES_AND_REVERSED
/************************ PER WINDOW BINDINGS ************************/

View File

@@ -48,7 +48,7 @@
#include <config.h>
#include <meta/main.h>
#include <meta/util.h>
#include "util-private.h"
#include "display-private.h"
#include <meta/errors.h>
#include "ui.h"
@@ -58,6 +58,7 @@
#include "meta-wayland-private.h"
#include <glib-object.h>
#include <glib-unix.h>
#include <gdk/gdkx.h>
#include <stdlib.h>
@@ -190,6 +191,7 @@ static gchar *opt_client_id;
static gboolean opt_replace_wm;
static gboolean opt_disable_sm;
static gboolean opt_sync;
static gboolean opt_wayland;
static GOptionEntry meta_options[] = {
{
@@ -227,6 +229,12 @@ static GOptionEntry meta_options[] = {
N_("Make X calls synchronous"),
NULL
},
{
"wayland", 0, 0, G_OPTION_ARG_NONE,
&opt_wayland,
N_("Run as a wayland compositor"),
NULL
},
{NULL}
};
@@ -248,6 +256,14 @@ meta_get_option_context (void)
bindtextdomain (GETTEXT_PACKAGE, MUTTER_LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
/* We must set the windowing backend here, because Clutter creates the backend
object when the first call is made.
We consider running from mutter-launch equivalent to running from bare metal.
*/
if (getenv ("WESTON_LAUNCHER_SOCK"))
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
ctx = g_option_context_new (NULL);
g_option_context_add_main_entries (ctx, meta_options, GETTEXT_PACKAGE);
g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
@@ -352,59 +368,12 @@ meta_finalize (void)
meta_wayland_finalize ();
}
static int signal_pipe_fds[2] = { -1, -1 };
static void
signal_handler (int signum)
{
if (signal_pipe_fds[1] >= 0)
{
switch (signum)
{
case SIGTERM:
write (signal_pipe_fds[1], "T", 1);
break;
default:
break;
}
}
}
static gboolean
on_signal (GIOChannel *source,
GIOCondition condition,
void *data)
on_sigterm (gpointer user_data)
{
char signal;
int count;
meta_quit (EXIT_SUCCESS);
for (;;)
{
count = read (signal_pipe_fds[0], &signal, 1);
if (count == EINTR)
continue;
if (count < 0)
{
const char *msg = strerror (errno);
g_warning ("Error handling signal: %s", msg);
}
if (count != 1)
{
g_warning ("Unexpectedly failed to read byte from signal pipe\n");
return TRUE;
}
break;
}
switch (signal)
{
case 'T': /* SIGTERM */
meta_quit (META_EXIT_SUCCESS);
break;
default:
g_warning ("Spurious character '%c' read from signal pipe", signal);
}
return TRUE;
return G_SOURCE_REMOVE;
}
/**
@@ -418,7 +387,6 @@ meta_init (void)
{
struct sigaction act;
sigset_t empty_mask;
GIOChannel *channel;
sigemptyset (&empty_mask);
act.sa_handler = SIG_IGN;
@@ -433,26 +401,15 @@ meta_init (void)
g_strerror (errno));
#endif
if (pipe (signal_pipe_fds) != 0)
g_printerr ("Failed to create signal pipe: %s\n",
g_strerror (errno));
channel = g_io_channel_unix_new (signal_pipe_fds[0]);
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_signal, NULL);
g_io_channel_set_close_on_unref (channel, TRUE);
g_io_channel_unref (channel);
act.sa_handler = &signal_handler;
if (sigaction (SIGTERM, &act, NULL) < 0)
g_printerr ("Failed to register SIGTERM handler: %s\n",
g_strerror (errno));
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
if (g_getenv ("MUTTER_VERBOSE"))
meta_set_verbose (TRUE);
if (g_getenv ("MUTTER_DEBUG"))
meta_set_debugging (TRUE);
meta_set_is_wayland_compositor (opt_wayland);
if (g_get_home_dir ())
if (chdir (g_get_home_dir ()) < 0)
meta_warning ("Could not change to home directory %s.\n",

View File

@@ -25,6 +25,7 @@
#define META_CURSOR_TRACKER_PRIVATE_H
#include <meta/meta-cursor-tracker.h>
#include <wayland-server.h>
#include <clutter/clutter.h>
gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
@@ -33,10 +34,10 @@ gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursor cursor);
void meta_cursor_tracker_revert_root (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
CoglTexture2D *texture,
int hot_x,
int hot_y);
void meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,

View File

@@ -24,50 +24,65 @@
/**
* SECTION:cursor-tracker
* @title: MetaCursorTracker
* @short_description: Mutter cursor tracking helper
* @short_description: Mutter cursor tracking helper. Originally only
* tracking the cursor image, now more of a "core
* pointer abstraction"
*/
#include <config.h>
#include <string.h>
#include <meta/main.h>
#include <meta/util.h>
#include <meta/errors.h>
#include <cogl/cogl.h>
#include <cogl/cogl-wayland-server.h>
#include <clutter/clutter.h>
#include <gbm.h>
#include <gdk/gdk.h>
#include <X11/cursorfont.h>
#include <X11/extensions/Xfixes.h>
#include <X11/Xcursor/Xcursor.h>
#include "meta-cursor-tracker-private.h"
#include "screen-private.h"
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
#include "monitor-private.h"
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
typedef struct {
CoglTexture2D *texture;
struct gbm_bo *bo;
int hot_x, hot_y;
int ref_count;
} MetaCursorReference;
struct _MetaCursorTracker {
GObject parent_instance;
MetaScreen *screen;
gboolean is_showing;
gboolean has_cursor;
gboolean has_hw_cursor;
CoglTexture2D *sprite;
int hot_x, hot_y;
CoglTexture2D *root_cursor;
int root_hot_x, root_hot_y;
CoglTexture2D *default_cursor;
MetaCursorReference *sprite;
MetaCursorReference *root_cursor;
MetaCursorReference *default_cursors[META_CURSOR_LAST];
int current_x, current_y;
cairo_rectangle_int_t current_rect;
cairo_rectangle_int_t previous_rect;
MetaRectangle current_rect;
MetaRectangle previous_rect;
gboolean previous_is_valid;
CoglPipeline *pipeline;
int drm_fd;
struct gbm_device *gbm;
};
struct _MetaCursorTrackerClass {
@@ -83,6 +98,409 @@ enum {
static guint signals[LAST_SIGNAL];
static void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
MetaCursorReference *sprite);
static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
MetaCRTC *crtc,
gboolean has_hw_cursor);
static MetaCursorReference *
meta_cursor_reference_ref (MetaCursorReference *self)
{
g_assert (self->ref_count > 0);
self->ref_count++;
return self;
}
static void
meta_cursor_reference_unref (MetaCursorReference *self)
{
self->ref_count--;
if (self->ref_count == 0)
{
cogl_object_unref (self->texture);
if (self->bo)
gbm_bo_destroy (self->bo);
g_slice_free (MetaCursorReference, self);
}
}
static void
translate_meta_cursor (MetaCursor cursor,
guint *glyph_out,
const char **name_out)
{
guint glyph = XC_num_glyphs;
const char *name = NULL;
switch (cursor)
{
case META_CURSOR_DEFAULT:
glyph = XC_left_ptr;
break;
case META_CURSOR_NORTH_RESIZE:
glyph = XC_top_side;
break;
case META_CURSOR_SOUTH_RESIZE:
glyph = XC_bottom_side;
break;
case META_CURSOR_WEST_RESIZE:
glyph = XC_left_side;
break;
case META_CURSOR_EAST_RESIZE:
glyph = XC_right_side;
break;
case META_CURSOR_SE_RESIZE:
glyph = XC_bottom_right_corner;
break;
case META_CURSOR_SW_RESIZE:
glyph = XC_bottom_left_corner;
break;
case META_CURSOR_NE_RESIZE:
glyph = XC_top_right_corner;
break;
case META_CURSOR_NW_RESIZE:
glyph = XC_top_left_corner;
break;
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
glyph = XC_fleur;
break;
case META_CURSOR_BUSY:
glyph = XC_watch;
break;
case META_CURSOR_DND_IN_DRAG:
name = "dnd-none";
break;
case META_CURSOR_DND_MOVE:
name = "dnd-move";
break;
case META_CURSOR_DND_COPY:
name = "dnd-copy";
break;
case META_CURSOR_DND_UNSUPPORTED_TARGET:
name = "dnd-none";
break;
case META_CURSOR_POINTING_HAND:
glyph = XC_hand2;
break;
case META_CURSOR_CROSSHAIR:
glyph = XC_crosshair;
break;
case META_CURSOR_IBEAM:
glyph = XC_xterm;
break;
default:
g_assert_not_reached ();
glyph = 0; /* silence compiler */
break;
}
*glyph_out = glyph;
*name_out = name;
}
static Cursor
load_cursor_on_server (MetaDisplay *display,
MetaCursor cursor)
{
Cursor xcursor;
guint glyph;
const char *name;
translate_meta_cursor (cursor, &glyph, &name);
if (name != NULL)
xcursor = XcursorLibraryLoadCursor (display->xdisplay, name);
else
xcursor = XCreateFontCursor (display->xdisplay, glyph);
return xcursor;
}
Cursor
meta_display_create_x_cursor (MetaDisplay *display,
MetaCursor cursor)
{
return load_cursor_on_server (display, cursor);
}
static XcursorImage *
load_cursor_on_client (MetaDisplay *display,
MetaCursor cursor)
{
XcursorImage *image;
guint glyph;
const char *name;
const char *theme = XcursorGetTheme (display->xdisplay);
int size = XcursorGetDefaultSize (display->xdisplay);
translate_meta_cursor (cursor, &glyph, &name);
if (name != NULL)
image = XcursorLibraryLoadImage (name, theme, size);
else
image = XcursorShapeLoadImage (glyph, theme, size);
return image;
}
static MetaCursorReference *
meta_cursor_reference_from_theme (MetaCursorTracker *tracker,
MetaCursor cursor)
{
XcursorImage *image;
int width, height, rowstride;
CoglPixelFormat cogl_format;
uint32_t gbm_format;
ClutterBackend *clutter_backend;
CoglContext *cogl_context;
MetaCursorReference *self;
image = load_cursor_on_client (tracker->screen->display, cursor);
if (!image)
return NULL;
width = image->width;
height = image->height;
rowstride = width * 4;
gbm_format = GBM_FORMAT_ARGB8888;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
#else
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
#endif
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->hot_x = image->xhot;
self->hot_y = image->yhot;
clutter_backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
self->texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
COGL_PIXEL_FORMAT_ANY,
rowstride,
(uint8_t*)image->pixels,
NULL);
if (tracker->gbm)
{
if (width > 64 || height > 64)
{
meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
goto out;
}
if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
{
uint32_t buf[64 * 64];
int i;
self->bo = gbm_bo_create (tracker->gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 64, image->pixels + i * width, width * 4);
gbm_bo_write (self->bo, buf, 64 * 64 * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
out:
XcursorImageDestroy (image);
return self;
}
static MetaCursorReference *
meta_cursor_reference_take_texture (CoglTexture2D *texture)
{
MetaCursorReference *self;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
self->texture = texture;
return self;
}
static MetaCursorReference *
meta_cursor_reference_from_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
ClutterBackend *backend;
CoglContext *cogl_context;
MetaCursorReference *self;
CoglPixelFormat cogl_format, cogl_internal_format;
struct wl_shm_buffer *shm_buffer;
uint32_t gbm_format;
self = g_slice_new0 (MetaCursorReference);
self->ref_count = 1;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
int width = wl_shm_buffer_get_width (shm_buffer);
int height = wl_shm_buffer_get_height (shm_buffer);
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
cogl_internal_format = COGL_PIXEL_FORMAT_ANY;
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
cogl_internal_format = COGL_PIXEL_FORMAT_RGB_888;
gbm_format = GBM_FORMAT_XRGB8888;
break;
#else
case WL_SHM_FORMAT_ARGB8888:
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
cogl_internal_format = COGL_PIXEL_FORMAT_ANY;
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
cogl_internal_format = COGL_PIXEL_FORMAT_BGR_888;
gbm_format = GBM_FORMAT_XRGB8888;
break;
#endif
default:
g_warn_if_reached ();
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
cogl_internal_format = COGL_PIXEL_FORMAT_ANY;
gbm_format = GBM_FORMAT_ARGB8888;
}
self->texture = cogl_texture_2d_new_from_data (cogl_context,
width, height,
cogl_format,
cogl_internal_format,
rowstride,
wl_shm_buffer_get_data (shm_buffer),
NULL);
if (width > 64 || height > 64)
{
meta_warning ("Invalid cursor size (must be at most 64x64), falling back to software (GL) cursors\n");
return self;
}
if (tracker->gbm)
{
if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
{
uint8_t *data;
uint8_t buf[4 * 64 * 64];
int i;
self->bo = gbm_bo_create (tracker->gbm, 64, 64,
gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
data = wl_shm_buffer_get_data (shm_buffer);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * 64, data + i * rowstride, 4 * width);
gbm_bo_write (self->bo, buf, 64 * 64 * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
}
else
{
int width, height;
self->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
width = cogl_texture_get_width (COGL_TEXTURE (self->texture));
height = cogl_texture_get_height (COGL_TEXTURE (self->texture));
/* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
that, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU access to the data, but it's not
possible if the buffer is in GPU memory (and possibly tiled too), so if we
don't get the right size, we fallback to GL.
*/
if (width != 64 || height != 64)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return self;
}
if (tracker->gbm)
{
cogl_format = cogl_texture_get_format (COGL_TEXTURE (self->texture));
switch (cogl_format)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
case COGL_PIXEL_FORMAT_ARGB_8888:
gbm_format = GBM_FORMAT_BGRA8888;
break;
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
case COGL_PIXEL_FORMAT_BGRA_8888:
break;
case COGL_PIXEL_FORMAT_RGB_888:
break;
#else
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
case COGL_PIXEL_FORMAT_ARGB_8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
case COGL_PIXEL_FORMAT_BGRA_8888:
gbm_format = GBM_FORMAT_BGRA8888;
break;
case COGL_PIXEL_FORMAT_RGB_888:
gbm_format = GBM_FORMAT_RGB888;
break;
#endif
default:
meta_warning ("Unknown cogl format %d\n", cogl_format);
return self;
}
if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
GBM_BO_USE_CURSOR_64X64))
{
self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer, GBM_BO_USE_CURSOR_64X64);
if (!self->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
}
return self;
}
static void
meta_cursor_tracker_init (MetaCursorTracker *self)
{
@@ -98,15 +516,21 @@ static void
meta_cursor_tracker_finalize (GObject *object)
{
MetaCursorTracker *self = META_CURSOR_TRACKER (object);
int i;
if (self->sprite)
cogl_object_unref (self->sprite);
meta_cursor_reference_unref (self->sprite);
if (self->root_cursor)
cogl_object_unref (self->root_cursor);
if (self->default_cursor)
cogl_object_unref (self->default_cursor);
meta_cursor_reference_unref (self->root_cursor);
for (i = 0; i < META_CURSOR_LAST; i++)
if (self->default_cursors[i])
meta_cursor_reference_unref (self->default_cursors[i]);
if (self->pipeline)
cogl_object_unref (self->pipeline);
if (self->gbm)
gbm_device_destroy (self->gbm);
G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
}
@@ -126,13 +550,41 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
G_TYPE_NONE, 0);
}
#ifdef HAVE_WAYLAND
static void
on_monitors_changed (MetaMonitorManager *monitors,
MetaCursorTracker *tracker)
{
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
if (!tracker->has_hw_cursor)
return;
/* Go through the new list of monitors, find out where the cursor is */
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
for (i = 0; i < n_crtcs; i++)
{
MetaRectangle *rect = &crtcs[i].rect;
gboolean has;
has = meta_rectangle_overlap (&tracker->current_rect, rect);
/* Need to do it unconditionally here, our tracking is
wrong because we reloaded the CRTCs */
meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
}
}
static MetaCursorTracker *
make_wayland_cursor_tracker (MetaScreen *screen)
{
MetaWaylandCompositor *compositor;
CoglContext *ctx;
MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
MetaMonitorManager *monitors;
MetaCursorTracker *self;
self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
self->screen = screen;
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
@@ -141,9 +593,16 @@ make_wayland_cursor_tracker (MetaScreen *screen)
compositor = meta_wayland_compositor_get_default ();
compositor->seat->cursor_tracker = self;
self->drm_fd = compositor->drm_fd;
if (self->drm_fd >= 0)
self->gbm = gbm_create_device (compositor->drm_fd);
monitors = meta_monitor_manager_get ();
g_signal_connect_object (monitors, "monitors-changed",
G_CALLBACK (on_monitors_changed), self, 0);
return self;
}
#endif
static MetaCursorTracker *
make_x11_cursor_tracker (MetaScreen *screen)
@@ -201,7 +660,7 @@ meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
if (notify_event->subtype != XFixesDisplayCursorNotify)
return FALSE;
g_clear_pointer (&tracker->sprite, cogl_object_unref);
g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
return TRUE;
@@ -264,9 +723,9 @@ ensure_xfixes_cursor (MetaCursorTracker *tracker)
if (sprite != NULL)
{
tracker->sprite = sprite;
tracker->hot_x = cursor_image->xhot;
tracker->hot_y = cursor_image->yhot;
tracker->sprite = meta_cursor_reference_take_texture (sprite);
tracker->sprite->hot_x = cursor_image->xhot;
tracker->sprite->hot_y = cursor_image->yhot;
}
XFree (cursor_image);
}
@@ -284,7 +743,10 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
if (!meta_is_wayland_compositor ())
ensure_xfixes_cursor (tracker);
return COGL_TEXTURE (tracker->sprite);
if (tracker->sprite)
return COGL_TEXTURE (tracker->sprite->texture);
else
return NULL;
}
/**
@@ -304,32 +766,34 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
if (!meta_is_wayland_compositor ())
ensure_xfixes_cursor (tracker);
if (x)
*x = tracker->hot_x;
if (y)
*y = tracker->hot_y;
if (tracker->sprite)
{
if (x)
*x = tracker->sprite->hot_x;
if (y)
*y = tracker->sprite->hot_y;
}
else
{
if (x)
*x = 0;
if (y)
*y = 0;
}
}
static void
ensure_wayland_cursor (MetaCursorTracker *tracker)
static MetaCursorReference *
ensure_wayland_cursor (MetaCursorTracker *tracker,
MetaCursor cursor)
{
CoglBitmap *bitmap;
char *filename;
if (tracker->default_cursors[cursor])
return tracker->default_cursors[cursor];
if (tracker->default_cursor)
return;
tracker->default_cursors[cursor] = meta_cursor_reference_from_theme (tracker, cursor);
if (!tracker->default_cursors[cursor])
meta_warning ("Failed to load cursor from theme\n");
filename = g_build_filename (MUTTER_PKGDATADIR,
"cursors/left_ptr.png",
NULL);
bitmap = cogl_bitmap_new_from_file (filename, NULL);
tracker->default_cursor = cogl_texture_2d_new_from_bitmap (bitmap,
COGL_PIXEL_FORMAT_ANY,
NULL);
cogl_object_unref (bitmap);
g_free (filename);
return tracker->default_cursors[cursor];
}
void
@@ -349,45 +813,115 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
/* Now update the real root cursor */
if (meta_is_wayland_compositor ())
{
/* FIXME! We need to load all the other cursors too */
ensure_wayland_cursor (tracker);
MetaCursorReference *ref;
g_clear_pointer (&tracker->root_cursor, cogl_object_unref);
tracker->root_cursor = cogl_object_ref (tracker->default_cursor);
tracker->root_hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
tracker->root_hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
ref = ensure_wayland_cursor (tracker, cursor);
g_clear_pointer (&tracker->root_cursor, meta_cursor_reference_unref);
tracker->root_cursor = meta_cursor_reference_ref (ref);
}
}
void
meta_cursor_tracker_revert_root (MetaCursorTracker *tracker)
{
meta_cursor_tracker_set_sprite (tracker,
tracker->root_cursor,
tracker->root_hot_x,
tracker->root_hot_y);
meta_cursor_tracker_set_sprite (tracker, tracker->root_cursor);
}
static void
update_hw_cursor (MetaCursorTracker *tracker)
{
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
gboolean enabled;
enabled = tracker->has_cursor && tracker->sprite->bo != NULL;
tracker->has_hw_cursor = enabled;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
for (i = 0; i < n_crtcs; i++)
{
MetaRectangle *rect = &crtcs[i].rect;
gboolean has;
has = enabled && meta_rectangle_overlap (&tracker->current_rect, rect);
if (has || crtcs[i].has_hw_cursor)
meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
}
}
static void
move_hw_cursor (MetaCursorTracker *tracker)
{
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL);
g_assert (tracker->has_hw_cursor);
for (i = 0; i < n_crtcs; i++)
{
MetaRectangle *rect = &crtcs[i].rect;
gboolean has;
has = meta_rectangle_overlap (&tracker->current_rect, rect);
if (has != crtcs[i].has_hw_cursor)
meta_cursor_tracker_set_crtc_has_hw_cursor (tracker, &crtcs[i], has);
if (has)
drmModeMoveCursor (tracker->drm_fd, crtcs[i].crtc_id,
tracker->current_rect.x - rect->x,
tracker->current_rect.y - rect->y);
}
}
void
meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
CoglTexture2D *sprite,
int hot_x,
int hot_y)
meta_cursor_tracker_set_buffer (MetaCursorTracker *tracker,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
MetaCursorReference *new_cursor;
if (buffer)
{
new_cursor = meta_cursor_reference_from_buffer (tracker, buffer, hot_x, hot_y);
meta_cursor_tracker_set_sprite (tracker, new_cursor);
meta_cursor_reference_unref (new_cursor);
}
else
meta_cursor_tracker_set_sprite (tracker, NULL);
}
static void
meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
MetaCursorReference *sprite)
{
g_assert (meta_is_wayland_compositor ());
g_clear_pointer (&tracker->sprite, cogl_object_unref);
if (sprite == tracker->sprite)
return;
g_clear_pointer (&tracker->sprite, meta_cursor_reference_unref);
if (sprite)
{
tracker->sprite = cogl_object_ref (sprite);
tracker->hot_x = hot_x;
tracker->hot_y = hot_y;
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite));
tracker->sprite = meta_cursor_reference_ref (sprite);
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite->texture));
}
else
cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
tracker->has_cursor = tracker->sprite != NULL && tracker->is_showing;
update_hw_cursor (tracker);
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y);
@@ -402,19 +936,24 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
tracker->current_x = new_x;
tracker->current_y = new_y;
tracker->current_rect.x = tracker->current_x - tracker->hot_x;
tracker->current_rect.y = tracker->current_y - tracker->hot_y;
if (tracker->sprite)
{
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite));
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite));
tracker->current_rect.x = tracker->current_x - tracker->sprite->hot_x;
tracker->current_rect.y = tracker->current_y - tracker->sprite->hot_y;
tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite->texture));
tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite->texture));
}
else
{
tracker->current_rect.x = 0;
tracker->current_rect.y = 0;
tracker->current_rect.width = 0;
tracker->current_rect.height = 0;
}
if (tracker->has_hw_cursor)
move_hw_cursor (tracker);
}
void
@@ -422,10 +961,9 @@ meta_cursor_tracker_paint (MetaCursorTracker *tracker)
{
g_assert (meta_is_wayland_compositor ());
if (tracker->sprite == NULL)
if (tracker->has_hw_cursor || !tracker->has_cursor)
return;
/* FIXME: try to use a DRM cursor when possible */
cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
tracker->pipeline,
tracker->current_rect.x,
@@ -443,16 +981,138 @@ void
meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
ClutterActor *stage)
{
cairo_rectangle_int_t clip;
g_assert (meta_is_wayland_compositor ());
if (tracker->previous_is_valid)
{
clutter_actor_queue_redraw_with_clip (stage, &tracker->previous_rect);
cairo_rectangle_int_t clip = {
.x = tracker->previous_rect.x,
.y = tracker->previous_rect.y,
.width = tracker->previous_rect.width,
.height = tracker->previous_rect.height
};
clutter_actor_queue_redraw_with_clip (stage, &clip);
tracker->previous_is_valid = FALSE;
}
if (tracker->sprite == NULL)
if (tracker->has_hw_cursor || !tracker->has_cursor)
return;
clutter_actor_queue_redraw_with_clip (stage, &tracker->current_rect);
clip.x = tracker->current_rect.x;
clip.y = tracker->current_rect.y;
clip.width = tracker->current_rect.width;
clip.height = tracker->current_rect.height;
clutter_actor_queue_redraw_with_clip (stage, &clip);
}
static void
meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *tracker,
MetaCRTC *crtc,
gboolean has)
{
if (has)
{
union gbm_bo_handle handle;
int width, height;
int hot_x, hot_y;
handle = gbm_bo_get_handle (tracker->sprite->bo);
width = gbm_bo_get_width (tracker->sprite->bo);
height = gbm_bo_get_height (tracker->sprite->bo);
hot_x = tracker->sprite->hot_x;
hot_y = tracker->sprite->hot_y;
drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, handle.u32,
width, height, hot_x, hot_y);
crtc->has_hw_cursor = TRUE;
}
else
{
drmModeSetCursor2 (tracker->drm_fd, crtc->crtc_id, 0, 0, 0, 0, 0);
crtc->has_hw_cursor = FALSE;
}
}
static void
get_pointer_position_gdk (int *x,
int *y,
int *mods)
{
GdkDeviceManager *gmanager;
GdkDevice *gdevice;
GdkScreen *gscreen;
gmanager = gdk_display_get_device_manager (gdk_display_get_default ());
gdevice = gdk_device_manager_get_client_pointer (gmanager);
gdk_device_get_position (gdevice, &gscreen, x, y);
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
}
static void
get_pointer_position_clutter (int *x,
int *y,
int *mods)
{
ClutterDeviceManager *cmanager;
ClutterInputDevice *cdevice;
ClutterPoint point;
cmanager = clutter_device_manager_get_default ();
cdevice = clutter_device_manager_get_core_device (cmanager, CLUTTER_POINTER_DEVICE);
clutter_input_device_get_coords (cdevice, NULL, &point);
*x = point.x;
*y = point.y;
*mods = clutter_input_device_get_modifier_state (cdevice);
}
void
meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
int *x,
int *y,
ClutterModifierType *mods)
{
/* We can't use the clutter interface when not running as a wayland compositor,
because we need to query the server, rather than using the last cached value.
OTOH, on wayland we can't use GDK, because that only sees the events
we forward to xwayland.
*/
if (meta_is_wayland_compositor ())
get_pointer_position_clutter (x, y, (int*)mods);
else
get_pointer_position_gdk (x, y, (int*)mods);
}
void
meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
gboolean visible)
{
if (visible == tracker->is_showing)
return;
tracker->is_showing = visible;
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
tracker->has_cursor = tracker->sprite != NULL && visible;
update_hw_cursor (tracker);
meta_cursor_tracker_queue_redraw (tracker, compositor->stage);
}
else
{
if (visible)
XFixesShowCursor (tracker->screen->display->xdisplay,
tracker->screen->xroot);
else
XFixesHideCursor (tracker->screen->display->xdisplay,
tracker->screen->xroot);
}
}

View File

@@ -77,7 +77,8 @@ typedef struct
guint64 timeout_msec;
/* x11 */
XSyncAlarm xalarm;
XSyncAlarm xalarm;
int idle_source_id;
/* wayland */
GSource *timeout_source;
@@ -116,6 +117,12 @@ fire_watch (MetaIdleMonitorWatch *watch)
monitor = watch->monitor;
g_object_ref (monitor);
if (watch->idle_source_id)
{
g_source_remove (watch->idle_source_id);
watch->idle_source_id = 0;
}
id = watch->id;
is_user_active_watch = (watch->timeout_msec == 0);
@@ -230,7 +237,7 @@ meta_idle_monitor_handle_xevent_all (XEvent *xevent)
{
int i;
for (i = 0; i < device_id_max; i++)
for (i = 0; i <= device_id_max; i++)
if (device_monitors[i])
meta_idle_monitor_handle_xevent (device_monitors[i], (XSyncAlarmNotifyEvent*)xevent);
}
@@ -286,6 +293,13 @@ idle_monitor_watch_free (MetaIdleMonitorWatch *watch)
return;
monitor = watch->monitor;
g_object_ref (monitor);
if (watch->idle_source_id)
{
g_source_remove (watch->idle_source_id);
watch->idle_source_id = 0;
}
if (watch->notify != NULL)
watch->notify (watch->user_data);
@@ -300,6 +314,7 @@ idle_monitor_watch_free (MetaIdleMonitorWatch *watch)
if (watch->timeout_source != NULL)
g_source_destroy (watch->timeout_source);
g_object_unref (monitor);
g_slice_free (MetaIdleMonitorWatch, watch);
}
@@ -480,6 +495,17 @@ static GSourceFuncs wayland_source_funcs = {
NULL, /* finalize */
};
static gboolean
fire_watch_idle (gpointer data)
{
MetaIdleMonitorWatch *watch = data;
watch->idle_source_id = 0;
fire_watch (watch);
return FALSE;
}
static MetaIdleMonitorWatch *
make_watch (MetaIdleMonitor *monitor,
guint64 timeout_msec,
@@ -511,13 +537,16 @@ make_watch (MetaIdleMonitor *monitor,
watch->timeout_source = source;
}
}
else
else if (monitor->user_active_alarm != None)
{
if (timeout_msec != 0)
{
watch->xalarm = _xsync_alarm_set (monitor, XSyncPositiveTransition, timeout_msec, TRUE);
g_hash_table_add (monitor->alarms, (gpointer) watch->xalarm);
if (meta_idle_monitor_get_idletime (monitor) > (gint64)timeout_msec)
watch->idle_source_id = g_idle_add (fire_watch_idle, watch);
}
else
{

View File

@@ -30,7 +30,7 @@
#define META_XRANDR_SHARED_H
typedef enum {
META_POWER_SAVE_UNKNOWN = -1,
META_POWER_SAVE_UNSUPPORTED = -1,
META_POWER_SAVE_ON = 0,
META_POWER_SAVE_STANDBY,
META_POWER_SAVE_SUSPEND,

View File

@@ -55,6 +55,8 @@ typedef struct {
char *serial;
} MetaOutputKey;
/* Keep this structure packed, so that we
can use memcmp */
typedef struct {
gboolean enabled;
MetaRectangle rect;
@@ -147,6 +149,13 @@ output_key_equal (const MetaOutputKey *one,
strcmp (one->serial, two->serial) == 0;
}
static gboolean
output_config_equal (const MetaOutputConfig *one,
const MetaOutputConfig *two)
{
return memcmp (one, two, sizeof (MetaOutputConfig)) == 0;
}
static unsigned int
config_hash (gconstpointer data)
{
@@ -180,6 +189,30 @@ config_equal (gconstpointer one,
return ok;
}
static gboolean
config_equal_full (gconstpointer one,
gconstpointer two)
{
const MetaConfiguration *c_one = one;
const MetaConfiguration *c_two = two;
unsigned int i;
gboolean ok;
if (c_one->n_outputs != c_two->n_outputs)
return FALSE;
ok = TRUE;
for (i = 0; i < c_one->n_outputs && ok; i++)
{
ok = output_key_equal (&c_one->keys[i],
&c_two->keys[i]);
ok = ok && output_config_equal (&c_one->outputs[i],
&c_two->outputs[i]);
}
return ok;
}
static void
meta_monitor_config_init (MetaMonitorConfig *self)
{
@@ -716,6 +749,9 @@ meta_monitor_config_load (MetaMonitorConfig *self)
free_output_key (&parser.key);
}
g_markup_parse_context_free (context);
g_free (contents);
}
MetaMonitorConfig *
@@ -878,6 +914,8 @@ make_laptop_lid_config (MetaConfiguration *reference)
MetaConfiguration *new;
unsigned int i;
gboolean has_primary;
int x_after, y_after;
int x_offset, y_offset;
g_assert (reference->n_outputs > 1);
@@ -886,6 +924,8 @@ make_laptop_lid_config (MetaConfiguration *reference)
new->keys = g_new0 (MetaOutputKey, reference->n_outputs);
new->outputs = g_new0 (MetaOutputConfig, reference->n_outputs);
x_after = G_MAXINT; y_after = G_MAXINT;
x_offset = 0; y_offset = 0;
for (i = 0; i < new->n_outputs; i++)
{
MetaOutputKey *current_key = &reference->keys[i];
@@ -898,14 +938,26 @@ make_laptop_lid_config (MetaConfiguration *reference)
if (g_str_has_prefix (current_key->connector, "LVDS") ||
g_str_has_prefix (current_key->connector, "eDP"))
new->outputs[i].enabled = FALSE;
{
new->outputs[i].enabled = FALSE;
x_after = current_output->rect.x;
y_after = current_output->rect.y;
x_offset = current_output->rect.width;
y_offset = current_output->rect.height;
}
else
/* This can potentially leave a "hole" in the screen,
but this is actually a good thing, as it means windows
don't move around.
*/
new->outputs[i] = *current_output;
}
for (i = 0; i < new->n_outputs; i++)
{
if (new->outputs[i].enabled)
{
if (new->outputs[i].rect.x > x_after)
new->outputs[i].rect.x -= x_offset;
if (new->outputs[i].rect.y > y_after)
new->outputs[i].rect.y -= y_offset;
}
}
has_primary = FALSE;
for (i = 0; i < new->n_outputs; i++)
@@ -1243,6 +1295,12 @@ meta_monitor_config_update_current (MetaMonitorConfig *self,
init_config_from_output (&current->outputs[i], &outputs[i]);
}
if (self->current && config_equal_full (current, self->current))
{
config_free (current);
return;
}
if (self->current && !self->current_is_stored)
config_free (self->current);

939
src/core/monitor-kms.c Normal file
View File

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

View File

@@ -116,6 +116,9 @@ struct _MetaOutput
*/
gboolean is_primary;
gboolean is_presentation;
gpointer driver_private;
GDestroyNotify driver_notify;
};
struct _MetaCRTC
@@ -133,16 +136,23 @@ struct _MetaCRTC
/* Used when changing configuration */
gboolean is_dirty;
/* Updated by MetaCursorTracker */
gboolean has_hw_cursor;
};
struct _MetaMonitorMode
{
/* The low-level ID of this mode, used to apply back configuration */
glong mode_id;
char *name;
int width;
int height;
float refresh_rate;
gpointer driver_private;
GDestroyNotify driver_notify;
};
/**
@@ -301,6 +311,8 @@ GType meta_monitor_manager_get_type (void);
void meta_monitor_manager_initialize (void);
MetaMonitorManager *meta_monitor_manager_get (void);
void meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager);
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
unsigned int *n_infos);
@@ -349,6 +361,18 @@ 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))
@@ -379,6 +403,11 @@ void meta_monitor_config_restore_previous (MetaMonitorConfig *con
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
void meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */
static inline gboolean

View File

@@ -351,13 +351,13 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
manager->power_save_mode = META_POWER_SAVE_OFF;
break;
default:
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
break;
}
}
else
{
manager->power_save_mode = META_POWER_SAVE_UNKNOWN;
manager->power_save_mode = META_POWER_SAVE_UNSUPPORTED;
}
XRRGetScreenSizeRange (manager_xrandr->xdisplay, DefaultRootWindow (manager_xrandr->xdisplay),
@@ -974,11 +974,58 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
XEvent *event)
{
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
unsigned int n_old_outputs, n_old_modes;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE;
XRRUpdateConfiguration (event);
/* Save the old structures, so they stay valid during the update */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
manager->serial++;
meta_monitor_manager_xrandr_read_current (manager);
/* Check if the current intended configuration has the same outputs
as the new real one, or if the event is a result of an XRandR call.
If so, we can go straight to rebuild the logical config and tell
the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with
new configTimestamps (bug 702804), and the driver may have
changed the EDID for some other reason (old broken qxl and vbox
drivers...).
*/
if (manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp ||
meta_monitor_config_match_current (manager->config, manager))
{
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
else
{
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
}
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
return TRUE;
}

View File

@@ -33,9 +33,10 @@
#include <clutter/clutter.h>
#include <meta/main.h>
#include <meta/util.h>
#include "util-private.h"
#include <meta/errors.h>
#include "monitor-private.h"
#include "meta-wayland-private.h"
#include "meta-dbus-xrandr.h"
@@ -59,67 +60,28 @@ static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface
G_DEFINE_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON,
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init));
static void free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
static void invalidate_logical_config (MetaMonitorManager *manager);
static void initialize_dbus_interface (MetaMonitorManager *manager);
static void
read_current_dummy (MetaMonitorManager *manager)
{
/* The dummy monitor config has:
- one enabled output, LVDS, primary, at 0x0 and 1024x768
- one free CRTC
- two disabled outputs
- three modes, 1024x768, 800x600 and 640x480
- no clones are possible (use different CRTCs)
Low-level IDs should be assigned sequentially, to
mimick what XRandR and KMS do
*/
manager->max_screen_width = 65535;
manager->max_screen_height = 65535;
manager->screen_width = 1024;
manager->screen_height = 768;
manager->modes = g_new0 (MetaMonitorMode, 6);
manager->n_modes = 6;
manager->modes = g_new0 (MetaMonitorMode, 1);
manager->n_modes = 1;
manager->modes[0].mode_id = 1;
manager->modes[0].mode_id = 0;
manager->modes[0].width = 1024;
manager->modes[0].height = 768;
manager->modes[0].refresh_rate = 60.0;
manager->modes[1].mode_id = 2;
manager->modes[1].width = 800;
manager->modes[1].height = 600;
manager->modes[1].refresh_rate = 60.0;
manager->crtcs = g_new0 (MetaCRTC, 1);
manager->n_crtcs = 1;
manager->modes[2].mode_id = 3;
manager->modes[2].width = 640;
manager->modes[2].height = 480;
manager->modes[2].refresh_rate = 60.0;
manager->modes[3].mode_id = 4;
manager->modes[3].width = 1920;
manager->modes[3].height = 1080;
manager->modes[3].refresh_rate = 60.0;
manager->modes[4].mode_id = 5;
manager->modes[4].width = 1920;
manager->modes[4].height = 1080;
manager->modes[4].refresh_rate = 55.0;
manager->modes[5].mode_id = 6;
manager->modes[5].width = 1600;
manager->modes[5].height = 900;
manager->modes[5].refresh_rate = 60.0;
manager->crtcs = g_new0 (MetaCRTC, 3);
manager->n_crtcs = 3;
manager->crtcs[0].crtc_id = 4;
manager->crtcs[0].crtc_id = 1;
manager->crtcs[0].rect.x = 0;
manager->crtcs[0].rect.y = 0;
manager->crtcs[0].rect.width = manager->modes[0].width;
@@ -130,111 +92,30 @@ read_current_dummy (MetaMonitorManager *manager)
manager->crtcs[0].is_dirty = FALSE;
manager->crtcs[0].logical_monitor = NULL;
manager->crtcs[1].crtc_id = 5;
manager->crtcs[1].rect.x = 0;
manager->crtcs[1].rect.y = 0;
manager->crtcs[1].rect.width = 0;
manager->crtcs[1].rect.height = 0;
manager->crtcs[1].current_mode = NULL;
manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL;
manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS;
manager->crtcs[1].is_dirty = FALSE;
manager->crtcs[1].logical_monitor = NULL;
manager->outputs = g_new0 (MetaOutput, 1);
manager->n_outputs = 1;
manager->crtcs[2].crtc_id = 5;
manager->crtcs[2].rect.x = 0;
manager->crtcs[2].rect.y = 0;
manager->crtcs[2].rect.width = 0;
manager->crtcs[2].rect.height = 0;
manager->crtcs[2].current_mode = NULL;
manager->crtcs[2].transform = WL_OUTPUT_TRANSFORM_NORMAL;
manager->crtcs[2].all_transforms = ALL_WL_TRANSFORMS;
manager->crtcs[2].is_dirty = FALSE;
manager->crtcs[2].logical_monitor = NULL;
manager->outputs = g_new0 (MetaOutput, 3);
manager->n_outputs = 3;
manager->outputs[0].crtc = NULL;
manager->outputs[0].output_id = 6;
manager->outputs[0].name = g_strdup ("HDMI");
manager->outputs[0].crtc = &manager->crtcs[0];
manager->outputs[0].output_id = 1;
manager->outputs[0].name = g_strdup ("LVDS");
manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[0].product = g_strdup ("unknown");
manager->outputs[0].serial = g_strdup ("0xC0F01A");
manager->outputs[0].width_mm = 510;
manager->outputs[0].height_mm = 287;
manager->outputs[0].serial = g_strdup ("0xC0FFEE");
manager->outputs[0].width_mm = 222;
manager->outputs[0].height_mm = 125;
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[0].preferred_mode = &manager->modes[3];
manager->outputs[0].n_modes = 5;
manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 5);
manager->outputs[0].preferred_mode = &manager->modes[0];
manager->outputs[0].n_modes = 1;
manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 1);
manager->outputs[0].modes[0] = &manager->modes[0];
manager->outputs[0].modes[1] = &manager->modes[1];
manager->outputs[0].modes[2] = &manager->modes[2];
manager->outputs[0].modes[3] = &manager->modes[3];
manager->outputs[0].modes[4] = &manager->modes[4];
manager->outputs[0].n_possible_crtcs = 3;
manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 3);
manager->outputs[0].n_possible_crtcs = 1;
manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 1);
manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0];
manager->outputs[0].possible_crtcs[1] = &manager->crtcs[1];
manager->outputs[0].possible_crtcs[2] = &manager->crtcs[2];
manager->outputs[0].n_possible_clones = 0;
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0);
manager->outputs[0].backlight = -1;
manager->outputs[0].backlight_min = 0;
manager->outputs[0].backlight_max = 0;
manager->outputs[1].crtc = &manager->crtcs[0];
manager->outputs[1].output_id = 7;
manager->outputs[1].name = g_strdup ("LVDS");
manager->outputs[1].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[1].product = g_strdup ("unknown");
manager->outputs[1].serial = g_strdup ("0xC0FFEE");
manager->outputs[1].width_mm = 222;
manager->outputs[1].height_mm = 125;
manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[1].preferred_mode = &manager->modes[5];
manager->outputs[1].n_modes = 4;
manager->outputs[1].modes = g_new0 (MetaMonitorMode *, 4);
manager->outputs[1].modes[0] = &manager->modes[0];
manager->outputs[1].modes[1] = &manager->modes[1];
manager->outputs[1].modes[2] = &manager->modes[2];
manager->outputs[1].modes[3] = &manager->modes[5];
manager->outputs[1].n_possible_crtcs = 3;
manager->outputs[1].possible_crtcs = g_new0 (MetaCRTC *, 3);
manager->outputs[1].possible_crtcs[0] = &manager->crtcs[0];
manager->outputs[1].possible_crtcs[1] = &manager->crtcs[1];
manager->outputs[1].possible_crtcs[2] = &manager->crtcs[2];
manager->outputs[1].n_possible_clones = 0;
manager->outputs[1].possible_clones = g_new0 (MetaOutput *, 0);
manager->outputs[1].backlight = -1;
manager->outputs[1].backlight_min = 0;
manager->outputs[1].backlight_max = 0;
manager->outputs[2].crtc = NULL;
manager->outputs[2].output_id = 8;
manager->outputs[2].name = g_strdup ("VGA");
manager->outputs[2].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[2].product = g_strdup ("unknown");
manager->outputs[2].serial = g_strdup ("0xC4FE");
manager->outputs[2].width_mm = 309;
manager->outputs[2].height_mm = 174;
manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[2].preferred_mode = &manager->modes[0];
manager->outputs[2].n_modes = 3;
manager->outputs[2].modes = g_new0 (MetaMonitorMode *, 3);
manager->outputs[2].modes[0] = &manager->modes[0];
manager->outputs[2].modes[1] = &manager->modes[1];
manager->outputs[2].modes[2] = &manager->modes[2];
manager->outputs[2].n_possible_crtcs = 3;
manager->outputs[2].possible_crtcs = g_new0 (MetaCRTC *, 3);
manager->outputs[2].possible_crtcs[0] = &manager->crtcs[0];
manager->outputs[2].possible_crtcs[1] = &manager->crtcs[1];
manager->outputs[2].possible_crtcs[2] = &manager->crtcs[2];
manager->outputs[2].n_possible_clones = 0;
manager->outputs[2].possible_clones = g_new0 (MetaOutput *, 0);
manager->outputs[2].backlight = -1;
manager->outputs[2].backlight_min = 0;
manager->outputs[2].backlight_max = 0;
}
static void
@@ -349,7 +230,7 @@ apply_config_dummy (MetaMonitorManager *manager,
manager->screen_width = screen_width;
manager->screen_height = screen_height;
invalidate_logical_config (manager);
meta_monitor_manager_rebuild_derived (manager);
}
static GBytes *
@@ -409,7 +290,7 @@ make_logical_config (MetaMonitorManager *manager)
for (j = 0; j < monitor_infos->len; j++)
{
MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, i);
MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, j);
if (meta_rectangle_equal (&crtc->rect,
&info->rect))
{
@@ -478,7 +359,16 @@ static GType
get_default_backend (void)
{
if (meta_is_wayland_compositor ())
return META_TYPE_MONITOR_MANAGER; /* FIXME: KMS */
{
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
if (meta_wayland_compositor_is_native (compositor))
return META_TYPE_MONITOR_MANAGER_KMS;
else
return META_TYPE_MONITOR_MANAGER;
}
else
return META_TYPE_MONITOR_MANAGER_XRANDR;
}
@@ -527,17 +417,18 @@ meta_monitor_manager_constructed (GObject *object)
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
int n_old_outputs;
unsigned int n_old_outputs, n_old_modes;
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
n_old_modes = manager->n_modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
free_output_array (old_outputs, n_old_outputs);
g_free (old_modes);
meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
g_free (old_crtcs);
}
@@ -553,11 +444,8 @@ meta_monitor_manager_set_power_save_mode (MetaMonitorManager *manager,
{
MetaMonitorManagerClass *klass;
if (mode == manager->power_save_mode)
return;
if (manager->power_save_mode == META_POWER_SAVE_UNKNOWN ||
mode == META_POWER_SAVE_UNKNOWN)
if (manager->power_save_mode == META_POWER_SAVE_UNSUPPORTED ||
mode == META_POWER_SAVE_UNSUPPORTED)
return;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
@@ -567,9 +455,9 @@ meta_monitor_manager_set_power_save_mode (MetaMonitorManager *manager,
manager->power_save_mode = mode;
}
static void
free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
void
meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs)
{
int i;
@@ -582,19 +470,39 @@ free_output_array (MetaOutput *old_outputs,
g_free (old_outputs[i].modes);
g_free (old_outputs[i].possible_crtcs);
g_free (old_outputs[i].possible_clones);
if (old_outputs[i].driver_notify)
old_outputs[i].driver_notify (&old_outputs[i]);
}
g_free (old_outputs);
}
void
meta_monitor_manager_free_mode_array (MetaMonitorMode *old_modes,
int n_old_modes)
{
int i;
for (i = 0; i < n_old_modes; i++)
{
g_free (old_modes[i].name);
if (old_modes[i].driver_notify)
old_modes[i].driver_notify (&old_modes[i]);
}
g_free (old_modes);
}
static void
meta_monitor_manager_finalize (GObject *object)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
free_output_array (manager->outputs, manager->n_outputs);
meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes);
g_free (manager->monitor_infos);
g_free (manager->modes);
g_free (manager->crtcs);
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
@@ -1453,12 +1361,21 @@ meta_monitor_manager_get_resources (MetaMonitorManager *manager,
MetaOutput **outputs,
unsigned int *n_outputs)
{
*modes = manager->modes;
*n_modes = manager->n_modes;
*crtcs = manager->crtcs;
*n_crtcs = manager->n_crtcs;
*outputs = manager->outputs;
*n_outputs = manager->n_outputs;
if (modes)
{
*modes = manager->modes;
*n_modes = manager->n_modes;
}
if (crtcs)
{
*crtcs = manager->crtcs;
*n_crtcs = manager->n_crtcs;
}
if (outputs)
{
*outputs = manager->outputs;
*n_outputs = manager->n_outputs;
}
}
int
@@ -1485,8 +1402,8 @@ meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
*height = manager->max_screen_height;
}
static void
invalidate_logical_config (MetaMonitorManager *manager)
void
meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager)
{
MetaMonitorInfo *old_monitor_infos;
@@ -1507,51 +1424,11 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
XEvent *event)
{
MetaMonitorManagerClass *klass;
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
int n_old_outputs;
gboolean changed;
klass = META_MONITOR_MANAGER_GET_CLASS (manager);
if (klass->handle_xevent)
changed = klass->handle_xevent (manager, event);
return klass->handle_xevent (manager, event);
else
changed = FALSE;
if (!changed)
return FALSE;
/* Save the old structures, so they stay valid during the update */
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
/* Check if the current intended configuration has the same outputs
as the new real one. If so, this was a result of an ApplyConfiguration
call (or a change from ourselves), and we can go straight to rebuild
the logical config and tell the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
*/
if (meta_monitor_config_match_current (manager->config, manager))
{
invalidate_logical_config (manager);
}
else
{
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
}
free_output_array (old_outputs, n_old_outputs);
g_free (old_modes);
g_free (old_crtcs);
return TRUE;
}

View File

@@ -25,6 +25,7 @@
#include <meta/main.h>
#include <meta/util.h>
#include <glib/gi18n-lib.h>
#include "meta-plugin-manager.h"
#include <glib.h>
@@ -46,15 +47,8 @@ print_version (const gchar *option_name,
}
static gchar *plugin = "default";
static gboolean opt_nested = FALSE;
GOptionEntry mutter_options[] = {
{
"nested", 0, 0, G_OPTION_ARG_NONE,
&opt_nested,
N_("Run nested as an application for testing"),
NULL,
},
{
"version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
print_version,
@@ -84,8 +78,6 @@ main (int argc, char **argv)
exit (1);
}
meta_set_is_wayland_compositor (opt_nested);
if (plugin)
meta_plugin_manager_load (plugin);

View File

@@ -31,7 +31,7 @@
#include <config.h>
#include <meta/prefs.h>
#include "ui.h"
#include <meta/util.h>
#include "util-private.h"
#include "meta-plugin-manager.h"
#include <glib.h>
#include <gio/gio.h>
@@ -1199,8 +1199,8 @@ maybe_give_disable_workarounds_warning (void)
{
first_disable = FALSE;
meta_warning (_("Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n"));
meta_warning ("Workarounds for broken applications disabled. "
"Some applications may not behave properly.\n");
}
}
@@ -1274,8 +1274,8 @@ titlebar_handler (GVariant *value,
if (desc == NULL)
{
meta_warning (_("Could not parse font description "
"\"%s\" from GSettings key %s\n"),
meta_warning ("Could not parse font description "
"\"%s\" from GSettings key %s\n",
string_value ? string_value : "(null)",
KEY_TITLEBAR_FONT);
return FALSE;
@@ -1340,8 +1340,8 @@ mouse_button_mods_handler (GVariant *value,
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to parse new GSettings value\n");
meta_warning (_("\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n"),
meta_warning ("\"%s\" found in configuration database is "
"not a valid value for mouse button modifier\n",
string_value);
return FALSE;
@@ -1906,7 +1906,7 @@ update_binding (MetaKeyPref *binding,
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to parse new GSettings value\n");
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
meta_warning ("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n",
strokes[i], binding->name);
/* Value is kept and will thus be removed next time we save the key.

View File

@@ -151,8 +151,6 @@ void meta_screen_foreach_window (MetaScreen *scree
MetaScreenWindowFunc func,
gpointer data);
void meta_screen_set_cursor (MetaScreen *screen,
MetaCursor cursor);
void meta_screen_update_cursor (MetaScreen *screen);
void meta_screen_tab_popup_create (MetaScreen *screen,

View File

@@ -33,7 +33,7 @@
#include <config.h>
#include "screen-private.h"
#include <meta/main.h>
#include <meta/util.h>
#include "util-private.h"
#include <meta/errors.h>
#include "window-private.h"
#include "frame.h"
@@ -391,6 +391,8 @@ int
meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
int index)
{
g_return_val_if_fail (index >= 0 && index < screen->n_monitor_infos, -1);
meta_screen_ensure_xinerama_indices (screen);
return screen->monitor_infos[index].xinerama_index;
@@ -579,7 +581,7 @@ meta_screen_new (MetaDisplay *display,
if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
{
meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"),
meta_warning ("Could not acquire window manager selection on screen %d display \"%s\"\n",
number, display->name);
XDestroyWindow (xdisplay, new_wm_sn_owner);
@@ -850,7 +852,7 @@ meta_screen_free (MetaScreen *screen,
meta_error_trap_push_with_return (screen->display);
XSelectInput (screen->display->xdisplay, screen->xroot, 0);
if (meta_error_trap_pop_with_return (screen->display) != Success)
meta_warning (_("Could not release screen %d on display \"%s\"\n"),
meta_warning ("Could not release screen %d on display \"%s\"\n",
screen->number, screen->display->name);
unset_wm_check_hint (screen);

View File

@@ -25,6 +25,8 @@
#include <config.h>
#include "util-private.h"
#include <meta/main.h>
#include "session.h"
#include <X11/Xatom.h>
@@ -531,6 +533,12 @@ die_callback (SmcConn smc_conn, SmPointer client_data)
* Anything that wants us to go away outside of session management
* can use kill().
*/
/* All of that is true - unless we're a wayland compositor. In which
* case the X server won't go down until we do, so we must die first.
*/
if (meta_is_wayland_compositor ())
meta_quit (0);
}
static void
@@ -840,14 +848,14 @@ save_state (void)
if (mkdir (mutter_dir, 0700) < 0 &&
errno != EEXIST)
{
meta_warning (_("Could not create directory '%s': %s\n"),
meta_warning ("Could not create directory '%s': %s\n",
mutter_dir, g_strerror (errno));
}
if (mkdir (session_dir, 0700) < 0 &&
errno != EEXIST)
{
meta_warning (_("Could not create directory '%s': %s\n"),
meta_warning ("Could not create directory '%s': %s\n",
session_dir, g_strerror (errno));
}
@@ -857,7 +865,7 @@ save_state (void)
if (outfile == NULL)
{
meta_warning (_("Could not open session file '%s' for writing: %s\n"),
meta_warning ("Could not open session file '%s' for writing: %s\n",
full_save_file (), g_strerror (errno));
goto out;
}
@@ -998,12 +1006,12 @@ save_state (void)
/* FIXME need a dialog for this */
if (ferror (outfile))
{
meta_warning (_("Error writing session file '%s': %s\n"),
meta_warning ("Error writing session file '%s': %s\n",
full_save_file (), g_strerror (errno));
}
if (fclose (outfile))
{
meta_warning (_("Error closing session file '%s': %s\n"),
meta_warning ("Error closing session file '%s': %s\n",
full_save_file (), g_strerror (errno));
}
}
@@ -1133,7 +1141,7 @@ load_state (const char *previous_save_file)
error:
meta_warning (_("Failed to parse saved session file: %s\n"),
meta_warning ("Failed to parse saved session file: %s\n",
error->message);
g_error_free (error);
@@ -1182,7 +1190,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("<mutter_session> attribute seen but we already have the session ID"));
"<mutter_session> attribute seen but we already have the session ID");
return;
}
@@ -1195,7 +1203,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
_("Unknown attribute %s on <%s> element"),
"Unknown attribute %s on <%s> element",
name, "mutter_session");
return;
}
@@ -1212,7 +1220,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("nested <window> tag"));
"nested <window> tag");
return;
}
@@ -1270,7 +1278,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
_("Unknown attribute %s on <%s> element"),
"Unknown attribute %s on <%s> element",
name, "window");
session_info_free (pd->info);
pd->info = NULL;
@@ -1302,7 +1310,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
_("Unknown attribute %s on <%s> element"),
"Unknown attribute %s on <%s> element",
name, "window");
session_info_free (pd->info);
pd->info = NULL;
@@ -1374,7 +1382,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
_("Unknown attribute %s on <%s> element"),
"Unknown attribute %s on <%s> element",
name, "maximized");
return;
}
@@ -1434,7 +1442,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
_("Unknown attribute %s on <%s> element"),
"Unknown attribute %s on <%s> element",
name, "geometry");
return;
}
@@ -1454,7 +1462,7 @@ start_element_handler (GMarkupParseContext *context,
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_UNKNOWN_ELEMENT,
_("Unknown element %s"),
"Unknown element %s",
element_name);
return;
}

View File

@@ -1051,7 +1051,6 @@ stack_tracker_event_received (MetaStackTracker *tracker,
tracker->xserver_serial = op->any.serial;
#warning "TODO: remove unused tracker->xserver_stack"
/* XXX: With the design we have ended up with it looks like we've
* ended up making it unnecessary to maintain tracker->xserver_stack
* since we only need an xserver_stack during the

View File

@@ -1724,14 +1724,12 @@ get_default_focus_window (MetaStack *stack,
* or top window in same group as not_this_one.
*/
MetaWindow *topmost_dock;
MetaWindow *transient_parent;
MetaWindow *topmost_in_group;
MetaWindow *topmost_overall;
MetaGroup *not_this_one_group;
GList *link;
topmost_dock = NULL;
transient_parent = NULL;
topmost_in_group = NULL;
topmost_overall = NULL;
@@ -1757,10 +1755,6 @@ get_default_focus_window (MetaStack *stack,
(workspace == NULL ||
meta_window_located_on_workspace (window, workspace)))
{
if (topmost_dock == NULL &&
window->type == META_WINDOW_DOCK)
topmost_dock = window;
if (not_this_one != NULL)
{
if (transient_parent == NULL &&
@@ -1778,10 +1772,6 @@ get_default_focus_window (MetaStack *stack,
topmost_in_group = window;
}
/* Note that DESKTOP windows can be topmost_overall so
* we prefer focusing desktop or other windows over
* focusing dock, even though docks are stacked higher.
*/
if (topmost_overall == NULL &&
window->type != META_WINDOW_DOCK &&
(!must_be_at_point ||
@@ -1803,7 +1793,7 @@ get_default_focus_window (MetaStack *stack,
else if (topmost_overall)
return topmost_overall;
else
return topmost_dock;
return NULL;
}
MetaWindow*

37
src/core/util-private.h Normal file
View File

@@ -0,0 +1,37 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* Mutter utilities */
/*
* Copyright (C) 2001 Havoc Pennington
* Copyright (C) 2005 Elijah Newren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef META_UTIL_PRIVATE_H
#define META_UTIL_PRIVATE_H
#include <meta/util.h>
#include <glib/gi18n-lib.h>
void meta_set_verbose (gboolean setting);
void meta_set_debugging (gboolean setting);
void meta_set_syncing (gboolean setting);
void meta_set_replace_current_wm (gboolean setting);
void meta_set_is_wayland_compositor (gboolean setting);
#endif

View File

@@ -31,7 +31,7 @@
#include <config.h>
#include <meta/common.h>
#include <meta/util.h>
#include "util-private.h"
#include <meta/main.h>
#include <clutter/clutter.h> /* For clutter_threads_add_repaint_func() */
@@ -82,7 +82,7 @@ ensure_logfile (void)
if (err != NULL)
{
meta_warning (_("Failed to open debug log: %s\n"),
meta_warning ("Failed to open debug log: %s\n",
err->message);
g_error_free (err);
return;
@@ -92,13 +92,13 @@ ensure_logfile (void)
if (logfile == NULL)
{
meta_warning (_("Failed to fdopen() log file %s: %s\n"),
meta_warning ("Failed to fdopen() log file %s: %s\n",
filename, strerror (errno));
close (fd);
}
else
{
g_printerr (_("Opened log file %s\n"), filename);
g_printerr ("Opened log file %s\n", filename);
}
g_free (filename);
@@ -274,7 +274,7 @@ meta_debug_spew_real (const char *format, ...)
out = logfile ? logfile : stderr;
if (no_prefix == 0)
utf8_fputs (_("Window manager: "), out);
utf8_fputs ("Window manager: ", out);
utf8_fputs (str, out);
fflush (out);
@@ -424,7 +424,7 @@ meta_bug (const char *format, ...)
#endif
if (no_prefix == 0)
utf8_fputs (_("Bug in window manager: "), out);
utf8_fputs ("Bug in window manager: ", out);
utf8_fputs (str, out);
fflush (out);
@@ -455,7 +455,7 @@ meta_warning (const char *format, ...)
#endif
if (no_prefix == 0)
utf8_fputs (_("Window manager warning: "), out);
utf8_fputs ("Window manager warning: ", out);
utf8_fputs (str, out);
fflush (out);
@@ -483,7 +483,7 @@ meta_fatal (const char *format, ...)
#endif
if (no_prefix == 0)
utf8_fputs (_("Window manager error: "), out);
utf8_fputs ("Window manager error: ", out);
utf8_fputs (str, out);
fflush (out);

View File

@@ -44,15 +44,7 @@
#include <X11/Xutil.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "meta-wayland-private.h"
/* XXX: We should find a nicer approach to deal with the
* circular dependency we have with the current headers
* (meta-wayland-private.h which typedefs MetaWaylandSurface
* also includes window-private.h) */
#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
typedef struct _MetaWaylandSurface MetaWaylandSurface;
#endif
#include "meta-wayland-types.h"
typedef struct _MetaWindowQueue MetaWindowQueue;
@@ -135,6 +127,7 @@ struct _MetaWindow
Window xtransient_for;
Window xgroup_leader;
Window xclient_leader;
MetaWindow *transient_for;
/* Initial workspace property */
int initial_workspace;
@@ -339,11 +332,6 @@ struct _MetaWindow
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
/* has a bounding shape mask */
guint has_shape : 1;
/* has an input shape mask */
guint has_input_shape : 1;
/* icon props have changed */
guint need_reread_icon : 1;
@@ -365,9 +353,15 @@ struct _MetaWindow
/* if non-NULL, the bounds of the window frame */
cairo_region_t *frame_bounds;
/* if non-NULL, the bounding shape region of the window */
cairo_region_t *shape_region;
/* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */
cairo_region_t *opaque_region;
/* the input shape region for picking */
cairo_region_t *input_region;
/* if TRUE, the we have the new form of sync request counter which
* also handles application frames */
guint extended_sync_request_counter : 1;
@@ -410,6 +404,12 @@ struct _MetaWindow
*/
MetaRectangle rect;
/* The size and position we want the window to be (i.e. what we last asked
* the client to configure).
* This is only used for wayland clients.
*/
MetaRectangle expected_rect;
gboolean has_custom_frame_extents;
GtkBorder custom_frame_extents;
@@ -607,6 +607,11 @@ void meta_window_move_resize_request(MetaWindow *window,
int y,
int width,
int height);
void meta_window_move_resize_wayland (MetaWindow *window,
int width,
int height,
int dx,
int dy);
gboolean meta_window_configure_request (MetaWindow *window,
XEvent *event);
gboolean meta_window_property_notify (MetaWindow *window,
@@ -673,7 +678,9 @@ void meta_window_update_layer (MetaWindow *window);
void meta_window_recalc_features (MetaWindow *window);
/* recalc_window_type is x11 only, wayland does its thing and then calls type_changed */
void meta_window_recalc_window_type (MetaWindow *window);
void meta_window_type_changed (MetaWindow *window);
void meta_window_stack_just_below (MetaWindow *window,
MetaWindow *below_this_one);
@@ -685,7 +692,6 @@ void meta_window_update_icon_now (MetaWindow *window);
void meta_window_update_role (MetaWindow *window);
void meta_window_update_net_wm_type (MetaWindow *window);
void meta_window_update_opaque_region (MetaWindow *window);
void meta_window_update_for_monitors_changed (MetaWindow *window);
void meta_window_update_on_all_workspaces (MetaWindow *window);
@@ -699,4 +705,32 @@ void meta_window_compute_tile_match (MetaWindow *window);
gboolean meta_window_updates_are_frozen (MetaWindow *window);
void meta_window_set_opaque_region (MetaWindow *window,
cairo_region_t *region);
void meta_window_update_opaque_region_x11 (MetaWindow *window);
void meta_window_set_input_region (MetaWindow *window,
cairo_region_t *region);
void meta_window_update_input_region_x11 (MetaWindow *window);
void meta_window_set_shape_region (MetaWindow *window,
cairo_region_t *region);
void meta_window_update_shape_region_x11 (MetaWindow *window);
void meta_window_set_title (MetaWindow *window,
const char *title);
void meta_window_set_wm_class (MetaWindow *window,
const char *wm_class,
const char *wm_instance);
void meta_window_set_gtk_dbus_properties (MetaWindow *window,
const char *application_id,
const char *unique_bus_name,
const char *appmenu_path,
const char *menubar_path,
const char *application_object_path,
const char *window_object_path);
void meta_window_set_transient_for (MetaWindow *window,
MetaWindow *parent);
#endif

View File

@@ -48,6 +48,7 @@
#include <X11/Xatom.h>
#include <unistd.h>
#include <string.h>
#include "util-private.h"
#ifndef HOST_NAME_MAX
/* Solaris headers apparently don't define this so do so manually; #326745 */
@@ -344,7 +345,7 @@ reload_net_wm_pid (MetaWindow *window,
gulong cardinal = (int) value->v.cardinal;
if (cardinal <= 0)
meta_warning (_("Application set a bogus _NET_WM_PID %lu\n"),
meta_warning ("Application set a bogus _NET_WM_PID %lu\n",
cardinal);
else
{
@@ -489,28 +490,19 @@ static void
set_window_title (MetaWindow *window,
const char *title)
{
char *str;
char *new_title = NULL;
gboolean modified =
set_title_text (window,
window->using_net_wm_visible_name,
title,
window->display->atom__NET_WM_VISIBLE_NAME,
&window->title);
&new_title);
window->using_net_wm_visible_name = modified;
/* strndup is a hack since GNU libc has broken %.10s */
str = g_strndup (window->title, 10);
g_free (window->desc);
window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str);
g_free (str);
meta_window_set_title (window, new_title);
if (window->frame)
meta_ui_set_frame_title (window->screen->ui,
window->frame->xwindow,
window->title);
g_object_notify (G_OBJECT (window), "title");
g_free (new_title);
}
static void
@@ -565,7 +557,7 @@ reload_opaque_region (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
meta_window_update_opaque_region (window);
meta_window_update_opaque_region_x11 (window);
}
static void
@@ -875,23 +867,15 @@ reload_wm_class (MetaWindow *window,
MetaPropValue *value,
gboolean initial)
{
if (window->res_class)
g_free (window->res_class);
if (window->res_name)
g_free (window->res_name);
window->res_class = NULL;
window->res_name = NULL;
if (value->type != META_PROP_VALUE_INVALID)
{
if (value->v.class_hint.res_name)
window->res_name = g_strdup (value->v.class_hint.res_name);
if (value->v.class_hint.res_class)
window->res_class = g_strdup (value->v.class_hint.res_class);
g_object_notify (G_OBJECT (window), "wm-class");
{
meta_window_set_wm_class (window,
value->v.class_hint.res_class,
value->v.class_hint.res_name);
}
else
{
meta_window_set_wm_class (window, NULL, NULL);
}
meta_verbose ("Window %s class: '%s' name: '%s'\n",
@@ -1534,7 +1518,7 @@ reload_transient_for (MetaWindow *window,
gboolean initial)
{
MetaWindow *parent = NULL;
Window transient_for, old_transient_for;
Window transient_for;
if (value->type != META_PROP_VALUE_INVALID)
{
@@ -1543,8 +1527,7 @@ reload_transient_for (MetaWindow *window,
parent = meta_display_lookup_x_window (window->display, transient_for);
if (!parent)
{
meta_warning (_("Invalid WM_TRANSIENT_FOR window 0x%lx specified "
"for %s.\n"),
meta_warning ("Invalid WM_TRANSIENT_FOR window 0x%lx specified for %s.\n",
transient_for, window->desc);
transient_for = None;
}
@@ -1554,8 +1537,7 @@ reload_transient_for (MetaWindow *window,
{
if (parent == window)
{
meta_warning (_("WM_TRANSIENT_FOR window 0x%lx for %s "
"would create loop.\n"),
meta_warning ("WM_TRANSIENT_FOR window 0x%lx for %s would create loop.\n",
transient_for, window->desc);
transient_for = None;
break;
@@ -1571,10 +1553,6 @@ reload_transient_for (MetaWindow *window,
if (transient_for == window->xtransient_for)
return;
if (meta_window_appears_focused (window) && window->xtransient_for != None)
meta_window_propagate_focus_appearance (window, FALSE);
old_transient_for = window->xtransient_for;
window->xtransient_for = transient_for;
window->transient_parent_is_root_window =
@@ -1586,46 +1564,14 @@ reload_transient_for (MetaWindow *window,
else
meta_verbose ("Window %s is not transient\n", window->desc);
/* may now be a dialog */
meta_window_recalc_window_type (window);
if (!window->constructing)
if (window->transient_parent_is_root_window || window->xtransient_for == None)
meta_window_set_transient_for (window, NULL);
else
{
/* If the window attaches, detaches, or changes attached
* parents, we need to destroy the MetaWindow and let a new one
* be created (which happens as a side effect of
* meta_window_unmanage()). The condition below is correct
* because we know window->xtransient_for has changed.
*/
if (window->attached || meta_window_should_attach_to_parent (window))
{
guint32 timestamp;
window->xtransient_for = old_transient_for;
timestamp = meta_display_get_current_time_roundtrip (window->display);
meta_window_unmanage (window, timestamp);
return;
}
parent = meta_display_lookup_x_window (window->display,
window->xtransient_for);
meta_window_set_transient_for (window, parent);
}
/* update stacking constraints */
if (!window->override_redirect)
meta_stack_update_transient (window->screen->stack, window);
/* possibly change its group. We treat being a window's transient as
* equivalent to making it your group leader, to work around shortcomings
* in programs such as xmms-- see #328211.
*/
if (window->xtransient_for != None &&
window->xgroup_leader != None &&
window->xtransient_for != window->xgroup_leader)
meta_window_group_leader_changed (window);
if (!window->constructing && !window->override_redirect)
meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
if (meta_window_appears_focused (window) && window->xtransient_for != None)
meta_window_propagate_focus_appearance (window, TRUE);
}
static void

File diff suppressed because it is too large Load Diff

View File

@@ -78,6 +78,7 @@ static void
meta_workspace_finalize (GObject *object)
{
/* Actual freeing done in meta_workspace_remove() for now */
G_OBJECT_CLASS (meta_workspace_parent_class)->finalize (object);
}
static void

View File

@@ -83,7 +83,7 @@ from The Open Group.
#include <config.h>
#include "xprops.h"
#include <meta/errors.h>
#include <meta/util.h>
#include "util-private.h"
#include "async-getprop.h"
#include "ui.h"
#include "mutter-Xatomtype.h"
@@ -152,7 +152,7 @@ validate_or_free_results (GetPropertyResults *results,
if (res_name == NULL)
res_name = "unknown";
meta_warning (_("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n"),
meta_warning ("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n",
results->xwindow,
prop_name ? prop_name : "(bad atom)",
expected_name ? expected_name : "(bad atom)",
@@ -408,7 +408,7 @@ utf8_string_from_results (GetPropertyResults *results,
char *name;
name = XGetAtomName (results->display->xdisplay, results->xatom);
meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8\n"),
meta_warning ("Property %s on window 0x%lx contained invalid UTF-8\n",
name, results->xwindow);
meta_XFree (name);
XFree (results->prop);
@@ -491,7 +491,7 @@ utf8_list_from_results (GetPropertyResults *results,
meta_error_trap_push (results->display);
name = XGetAtomName (results->display->xdisplay, results->xatom);
meta_error_trap_pop (results->display);
meta_warning (_("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n"),
meta_warning ("Property %s on window 0x%lx contained invalid UTF-8 for item %d in the list\n",
name, results->xwindow, i);
meta_XFree (name);
meta_XFree (results->prop);

View File

@@ -260,6 +260,13 @@ typedef enum
* @META_CURSOR_NW_RESIZE: Resize north-western corner cursor
* @META_CURSOR_MOVE_OR_RESIZE_WINDOW: Move or resize cursor
* @META_CURSOR_BUSY: Busy cursor
* @META_CURSOR_DND_IN_DRAG: DND in drag cursor
* @META_CURSOR_DND_MOVE: DND move cursor
* @META_CURSOR_DND_COPY: DND copy cursor
* @META_CURSOR_DND_UNSUPPORTED_TARGET: DND unsupported target
* @META_CURSOR_POINTING_HAND: pointing hand
* @META_CURSOR_CROSSHAIR: crosshair (action forbidden)
* @META_CURSOR_IBEAM: I-beam (text input)
*/
typedef enum
{
@@ -273,8 +280,15 @@ typedef enum
META_CURSOR_NE_RESIZE,
META_CURSOR_NW_RESIZE,
META_CURSOR_MOVE_OR_RESIZE_WINDOW,
META_CURSOR_BUSY
META_CURSOR_BUSY,
META_CURSOR_DND_IN_DRAG,
META_CURSOR_DND_MOVE,
META_CURSOR_DND_COPY,
META_CURSOR_DND_UNSUPPORTED_TARGET,
META_CURSOR_POINTING_HAND,
META_CURSOR_CROSSHAIR,
META_CURSOR_IBEAM,
META_CURSOR_LAST
} MetaCursor;
/**

View File

@@ -64,8 +64,8 @@ void meta_compositor_manage_screen (MetaCompositor *compositor,
void meta_compositor_unmanage_screen (MetaCompositor *compositor,
MetaScreen *screen);
void meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
MetaWindow *window);
void meta_compositor_window_shape_changed (MetaCompositor *compositor,
MetaWindow *window);
gboolean meta_compositor_process_event (MetaCompositor *compositor,
XEvent *event,

View File

@@ -28,6 +28,7 @@
#include <meta/types.h>
#include <meta/workspace.h>
#include <cogl/cogl.h>
#include <clutter/clutter.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))
@@ -47,4 +48,11 @@ void meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
int *y);
CoglTexture *meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker);
void meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
int *x,
int *y,
ClutterModifierType *mods);
void meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
gboolean visible);
#endif

View File

@@ -67,11 +67,12 @@ GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps);
void meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height);
gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x,
int y,
int width,
int height,
cairo_region_t *unobscured_region);
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
@@ -80,10 +81,12 @@ void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
cairo_region_t *shape_region);
/* Assumes ownership of clip_region */
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region);
void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
cairo_region_t *opaque_region);
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
cairo_rectangle_int_t *clip);

View File

@@ -419,13 +419,13 @@ typedef struct
*/
GSList *bindings;
/** for keybindings that can have shift or not like Alt+Tab */
/* for keybindings that can have shift or not like Alt+Tab */
gboolean add_shift:1;
/** for keybindings that apply only to a window */
/* for keybindings that apply only to a window */
gboolean per_window:1;
/** for keybindings not added with meta_display_add_keybinding() */
/* for keybindings not added with meta_display_add_keybinding() */
gboolean builtin:1;
} MetaKeyPref;

View File

@@ -114,4 +114,8 @@ void meta_screen_override_workspace_layout (MetaScreen *screen,
gboolean vertical_layout,
int n_rows,
int n_columns);
void meta_screen_set_cursor (MetaScreen *screen,
MetaCursor cursor);
#endif

View File

@@ -31,14 +31,9 @@
#include <meta/common.h>
gboolean meta_is_verbose (void);
void meta_set_verbose (gboolean setting);
gboolean meta_is_debugging (void);
void meta_set_debugging (gboolean setting);
gboolean meta_is_syncing (void);
void meta_set_syncing (gboolean setting);
void meta_set_replace_current_wm (gboolean setting);
gboolean meta_is_wayland_compositor (void);
void meta_set_is_wayland_compositor (gboolean setting);
void meta_debug_spew_real (const char *format,
...) G_GNUC_PRINTF (1, 2);
@@ -124,10 +119,6 @@ const char* meta_gravity_to_string (int gravity);
char* meta_external_binding_name_for_action (guint keybinding_action);
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x
char* meta_g_utf8_strndup (const gchar *src, gsize n);
void meta_free_gslist_and_elements (GSList *list_to_deep_free);

View File

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

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

@@ -28,7 +28,7 @@
#include <string.h>
#include "menu.h"
#include <meta/main.h>
#include <meta/util.h>
#include "util-private.h"
#include "core.h"
#include "metaaccellabel.h"
#include "ui.h"

View File

@@ -35,7 +35,7 @@
#include "metaaccellabel.h"
#include <gtk/gtk.h>
#include <string.h>
#include <meta/util.h>
#include "util-private.h"
static void meta_accel_label_destroy (GtkWidget *object);
static void meta_accel_label_finalize (GObject *object);

View File

@@ -23,7 +23,7 @@
#include <config.h>
#include "resizepopup.h"
#include <meta/util.h>
#include "util-private.h"
#include <gtk/gtk.h>
#include <gdk/gdkx.h>

View File

@@ -23,7 +23,7 @@
#include <config.h>
#include "theme-private.h"
#include <meta/util.h>
#include "util-private.h"
#include <string.h>
#include <stdlib.h>
@@ -430,7 +430,11 @@ locate_attributes (GMarkupParseContext *context,
while (name != NULL)
{
g_return_val_if_fail (retloc != NULL, FALSE);
if (retloc == NULL)
{
retval = FALSE;
goto out;
}
g_assert (n_attrs < MAX_ATTRS);
@@ -3212,9 +3216,6 @@ parse_style_set_element (GMarkupParseContext *context,
meta_frame_style_ref (frame_style);
info->style_set->tiled_right_styles[frame_focus] = frame_style;
break;
meta_frame_style_ref (frame_style);
info->style_set->tiled_right_styles[frame_focus] = frame_style;
break;
case META_FRAME_STATE_SHADED:
if (info->style_set->shaded_styles[frame_resize][frame_focus])
{

View File

@@ -39,7 +39,7 @@
#include <config.h>
#include "theme-private.h"
#include "frames.h" /* for META_TYPE_FRAMES */
#include <meta/util.h>
#include "util-private.h"
#include <meta/gradient.h>
#include <meta/prefs.h>
#include <gtk/gtk.h>

View File

@@ -33,6 +33,7 @@
#include "meta-wayland-data-device.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
static void
data_offer_accept (struct wl_client *client,
@@ -108,12 +109,12 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
offer->source = source;
offer->source_destroy_listener.notify = destroy_offer_data_source;
offer->resource = wl_client_add_object (wl_resource_get_client (target),
&wl_data_offer_interface,
&data_offer_interface,
0,
offer);
wl_resource_set_destructor (offer->resource, destroy_data_offer);
offer->resource = wl_resource_create (wl_resource_get_client (target),
&wl_data_offer_interface,
MIN (META_WL_DATA_OFFER_VERSION,
wl_resource_get_version (target)), 0);
wl_resource_set_implementation (offer->resource, &data_offer_interface,
offer, destroy_data_offer);
wl_resource_add_destroy_listener (source->resource,
&offer->source_destroy_listener);
@@ -150,42 +151,63 @@ static struct wl_data_source_interface data_source_interface = {
data_source_destroy
};
typedef struct {
MetaWaylandPointerGrab generic;
MetaWaylandSeat *seat;
struct wl_client *drag_client;
MetaWaylandSurface *drag_focus;
struct wl_resource *drag_focus_data_device;
struct wl_listener drag_focus_listener;
MetaWaylandSurface *drag_surface;
struct wl_listener drag_icon_listener;
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
} MetaWaylandDragGrab;
static void
destroy_drag_focus (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat = wl_container_of (listener, seat, drag_focus_listener);
MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener);
seat->drag_focus_resource = NULL;
grab->drag_focus_data_device = NULL;
}
static void
drag_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
MetaWaylandSeat *seat = drag_grab->seat;
struct wl_resource *resource, *offer = NULL;
struct wl_display *display;
guint32 serial;
wl_fixed_t sx, sy;
if (seat->drag_focus_resource)
if (drag_grab->drag_focus == surface)
return;
if (drag_grab->drag_focus_data_device)
{
wl_data_device_send_leave (seat->drag_focus_resource);
wl_list_remove (&seat->drag_focus_listener.link);
seat->drag_focus_resource = NULL;
seat->drag_focus = NULL;
wl_data_device_send_leave (drag_grab->drag_focus_data_device);
wl_list_remove (&drag_grab->drag_focus_listener.link);
drag_grab->drag_focus_data_device = NULL;
drag_grab->drag_focus = NULL;
}
if (!surface)
return;
if (!seat->drag_data_source &&
wl_resource_get_client (surface->resource) != seat->drag_client)
if (!drag_grab->drag_data_source &&
wl_resource_get_client (surface->resource) != drag_grab->drag_client)
return;
resource =
wl_resource_find_for_client (&seat->drag_resource_list,
wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (surface->resource));
if (!resource)
return;
@@ -193,68 +215,73 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
display = wl_client_get_display (wl_resource_get_client (resource));
serial = wl_display_next_serial (display);
if (seat->drag_data_source)
offer = meta_wayland_data_source_send_offer (seat->drag_data_source,
if (drag_grab->drag_data_source)
offer = meta_wayland_data_source_send_offer (drag_grab->drag_data_source,
resource);
meta_wayland_pointer_get_relative_coordinates (grab->pointer, surface, &sx, &sy);
wl_data_device_send_enter (resource, serial, surface->resource,
x, y, offer);
sx, sy, offer);
seat->drag_focus = surface;
seat->drag_focus_listener.notify = destroy_drag_focus;
wl_resource_add_destroy_listener (resource, &seat->drag_focus_listener);
seat->drag_focus_resource = resource;
grab->focus = surface;
drag_grab->drag_focus = surface;
drag_grab->drag_focus_data_device = resource;
drag_grab->drag_focus_listener.notify = destroy_drag_focus;
wl_resource_add_destroy_listener (resource, &drag_grab->drag_focus_listener);
}
static void
drag_grab_motion (MetaWaylandPointerGrab *grab,
guint32 time, wl_fixed_t x, wl_fixed_t y)
const ClutterEvent *event)
{
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
wl_fixed_t sx, sy;
if (seat->drag_focus_resource)
wl_data_device_send_motion (seat->drag_focus_resource, time, x, y);
if (drag_grab->drag_focus_data_device)
{
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
drag_grab->drag_focus,
&sx, &sy);
wl_data_device_send_motion (drag_grab->drag_focus_data_device,
clutter_event_get_time (event),
sx, sy);
}
}
static void
data_device_end_drag_grab (MetaWaylandSeat *seat)
data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
{
if (seat->drag_surface)
if (drag_grab->drag_surface)
{
seat->drag_surface = NULL;
wl_signal_emit (&seat->drag_icon_signal, NULL);
wl_list_remove (&seat->drag_icon_listener.link);
drag_grab->drag_surface = NULL;
wl_list_remove (&drag_grab->drag_icon_listener.link);
}
drag_grab_focus (&seat->drag_grab, NULL,
wl_fixed_from_int (0), wl_fixed_from_int (0));
if (drag_grab->drag_data_source)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
meta_wayland_pointer_end_grab (&seat->pointer);
drag_grab_focus (&drag_grab->generic, NULL, NULL);
seat->drag_data_source = NULL;
seat->drag_client = NULL;
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
g_slice_free (MetaWaylandDragGrab, drag_grab);
}
static void
drag_grab_button (MetaWaylandPointerGrab *grab,
guint32 time, guint32 button, guint32 state_w)
const ClutterEvent *event)
{
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
enum wl_pointer_button_state state = state_w;
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
MetaWaylandSeat *seat = drag_grab->seat;
ClutterEventType event_type = clutter_event_type (event);
if (seat->drag_focus_resource &&
seat->pointer.grab_button == button &&
state == WL_POINTER_BUTTON_STATE_RELEASED)
wl_data_device_send_drop (seat->drag_focus_resource);
if (drag_grab->drag_focus_data_device &&
drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
if (seat->pointer.button_count == 0 &&
state == WL_POINTER_BUTTON_STATE_RELEASED)
{
if (seat->drag_data_source)
wl_list_remove (&seat->drag_data_source_listener.link);
data_device_end_drag_grab (seat);
}
event_type == CLUTTER_BUTTON_RELEASE)
data_device_end_drag_grab (drag_grab);
}
static const MetaWaylandPointerGrabInterface drag_grab_interface = {
@@ -266,19 +293,20 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
static void
destroy_data_device_source (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat =
wl_container_of (listener, seat, drag_data_source_listener);
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_data_source_listener);
data_device_end_drag_grab (seat);
drag_grab->drag_data_source = NULL;
data_device_end_drag_grab (drag_grab);
}
static void
destroy_data_device_icon (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat =
wl_container_of (listener, seat, drag_icon_listener);
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_data_source_listener);
seat->drag_surface = NULL;
drag_grab->drag_surface = NULL;
}
static void
@@ -289,38 +317,40 @@ data_device_start_drag (struct wl_client *client,
struct wl_resource *icon_resource, guint32 serial)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
MetaWaylandDragGrab *drag_grab;
/* FIXME: Check that client has implicit grab on the origin
* surface that matches the given time. */
/* FIXME: Check that the data source type array isn't empty. */
seat->drag_grab.interface = &drag_grab_interface;
if (seat->pointer.grab != &seat->pointer.default_grab)
return;
seat->drag_client = client;
seat->drag_data_source = NULL;
drag_grab = g_slice_new0 (MetaWaylandDragGrab);
drag_grab->generic.interface = &drag_grab_interface;
drag_grab->generic.pointer = &seat->pointer;
drag_grab->drag_client = client;
if (source_resource)
{
seat->drag_data_source = wl_resource_get_user_data (source_resource);
seat->drag_data_source_listener.notify = destroy_data_device_source;
drag_grab->drag_data_source = wl_resource_get_user_data (source_resource);
drag_grab->drag_data_source_listener.notify = destroy_data_device_source;
wl_resource_add_destroy_listener (source_resource,
&seat->drag_data_source_listener);
&drag_grab->drag_data_source_listener);
}
if (icon_resource)
{
seat->drag_surface = wl_resource_get_user_data (icon_resource);
seat->drag_icon_listener.notify = destroy_data_device_icon;
drag_grab->drag_surface = wl_resource_get_user_data (icon_resource);
drag_grab->drag_icon_listener.notify = destroy_data_device_icon;
wl_resource_add_destroy_listener (icon_resource,
&seat->drag_icon_listener);
wl_signal_emit (&seat->drag_icon_signal, icon_resource);
&drag_grab->drag_icon_listener);
}
meta_wayland_pointer_set_focus (&seat->pointer, NULL,
wl_fixed_from_int (0),
wl_fixed_from_int (0));
meta_wayland_pointer_start_grab (&seat->pointer, &seat->drag_grab);
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab);
}
static void
@@ -338,13 +368,11 @@ destroy_selection_data_source (struct wl_listener *listener, void *data)
if (focus)
{
data_device =
wl_resource_find_for_client (&seat->drag_resource_list,
wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (focus));
if (data_device)
wl_data_device_send_selection (data_device, NULL);
}
wl_signal_emit (&seat->selection_signal, seat);
}
void
@@ -374,7 +402,7 @@ meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
if (focus)
{
data_device =
wl_resource_find_for_client (&seat->drag_resource_list,
wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (focus));
if (data_device && source)
{
@@ -389,8 +417,6 @@ meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
}
}
wl_signal_emit (&seat->selection_signal, seat);
if (source)
{
seat->selection_data_source_listener.notify =
@@ -465,12 +491,11 @@ create_data_source (struct wl_client *client,
return;
}
source->resource = wl_client_add_object (client,
&wl_data_source_interface,
&data_source_interface,
id,
source);
wl_resource_set_destructor (source->resource, destroy_data_source);
source->resource = wl_resource_create (client, &wl_data_source_interface,
MIN (META_WL_DATA_SOURCE_VERSION,
wl_resource_get_version (resource)), id);
wl_resource_set_implementation (source->resource, &data_source_interface,
source, destroy_data_source);
source->accept = client_source_accept;
source->send = client_source_send;
@@ -493,11 +518,11 @@ get_data_device (struct wl_client *client,
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *resource;
resource = wl_client_add_object (client, &wl_data_device_interface,
&data_device_interface, id, seat);
wl_list_insert (&seat->drag_resource_list, wl_resource_get_link (resource));
wl_resource_set_destructor (resource, unbind_data_device);
resource = wl_resource_create (client, &wl_data_device_interface,
MIN (META_WL_DATA_DEVICE_VERSION,
wl_resource_get_version (manager_resource)), id);
wl_resource_set_implementation (resource, &data_device_interface, seat, unbind_data_device);
wl_list_insert (&seat->data_device_resource_list, wl_resource_get_link (resource));
}
static const struct wl_data_device_manager_interface manager_interface = {
@@ -509,8 +534,11 @@ static void
bind_manager (struct wl_client *client,
void *data, guint32 version, guint32 id)
{
wl_client_add_object (client, &wl_data_device_manager_interface,
&manager_interface, id, NULL);
struct wl_resource *resource;
resource = wl_resource_create (client, &wl_data_device_manager_interface,
MIN (version, META_WL_DATA_DEVICE_MANAGER_VERSION), id);
wl_resource_set_implementation (resource, &manager_interface, NULL, NULL);
}
void
@@ -523,7 +551,7 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat)
if (!focus)
return;
data_device = wl_resource_find_for_client (&seat->drag_resource_list,
data_device = wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (focus));
if (!data_device)
return;
@@ -539,9 +567,10 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat)
int
meta_wayland_data_device_manager_init (struct wl_display *display)
{
if (wl_display_add_global (display,
&wl_data_device_manager_interface,
NULL, bind_manager) == NULL)
if (wl_global_create (display,
&wl_data_device_manager_interface,
META_WL_DATA_DEVICE_MANAGER_VERSION,
NULL, bind_manager) == NULL)
return -1;
return 0;

View File

@@ -56,8 +56,9 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <clutter/evdev/clutter-evdev.h>
#include "meta-wayland-keyboard.h"
#include "meta-wayland-private.h"
static MetaWaylandSeat *
meta_wayland_keyboard_get_seat (MetaWaylandKeyboard *keyboard)
@@ -201,7 +202,7 @@ lose_keyboard_focus (struct wl_listener *listener, void *data)
keyboard->focus_resource = NULL;
}
static void
static gboolean
default_grab_key (MetaWaylandKeyboardGrab *grab,
uint32_t time, uint32_t key, uint32_t state)
{
@@ -217,6 +218,8 @@ default_grab_key (MetaWaylandKeyboardGrab *grab,
serial = wl_display_next_serial (display);
wl_keyboard_send_key (resource, serial, time, key, state);
}
return resource != NULL;
}
static struct wl_resource *
@@ -258,12 +261,11 @@ default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
pointer->focus);
if (pr)
{
wl_keyboard_send_modifiers (pr,
serial,
keyboard->modifiers.mods_depressed,
keyboard->modifiers.mods_latched,
keyboard->modifiers.mods_locked,
keyboard->modifiers.group);
wl_keyboard_send_modifiers (pr, serial,
mods_depressed,
mods_latched,
mods_locked,
group);
}
}
}
@@ -274,10 +276,38 @@ static const MetaWaylandKeyboardGrabInterface
default_grab_modifiers,
};
static gboolean
modal_key (MetaWaylandKeyboardGrab *grab,
uint32_t time,
uint32_t key,
uint32_t state)
{
/* FALSE means: let the event through to clutter */
return FALSE;
}
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_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display)
struct wl_display *display,
gboolean is_evdev)
{
ClutterDeviceManager *manager;
memset (keyboard, 0, sizeof *keyboard);
wl_list_init (&keyboard->resource_list);
@@ -286,15 +316,22 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->default_grab.interface = &default_keyboard_grab_interface;
keyboard->default_grab.keyboard = keyboard;
keyboard->grab = &keyboard->default_grab;
wl_signal_init (&keyboard->focus_signal);
keyboard->display = display;
keyboard->xkb_context = xkb_context_new (0 /* flags */);
meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
&keyboard->xkb_names,
&keyboard->xkb_info);
&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);
}
return TRUE;
}
@@ -311,90 +348,64 @@ meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
close (xkb_info->keymap_fd);
}
static gboolean
state_equal (MetaWaylandXkbState *one,
MetaWaylandXkbState *two)
{
return one->mods_depressed == two->mods_depressed &&
one->mods_latched == two->mods_latched &&
one->mods_locked == two->mods_locked &&
one->group == two->group;
}
static void
set_modifiers (MetaWaylandKeyboard *keyboard,
guint32 serial,
ClutterModifierType modifier_state)
guint32 serial,
ClutterEvent *event)
{
MetaWaylandKeyboardGrab *grab = keyboard->grab;
uint32_t depressed_mods = 0;
uint32_t locked_mods = 0;
MetaWaylandXkbState new_state;
guint effective_state;
if (keyboard->last_modifier_state == modifier_state)
clutter_event_get_state_full (event,
NULL,
&new_state.mods_depressed,
&new_state.mods_latched,
&new_state.mods_locked,
&effective_state);
new_state.group = (effective_state >> 13) & 0x3;
if (state_equal (&keyboard->modifier_state, &new_state))
return;
if ((modifier_state & CLUTTER_SHIFT_MASK) &&
keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
if ((modifier_state & CLUTTER_LOCK_MASK) &&
keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
locked_mods |= (1 << keyboard->xkb_info.caps_mod);
if ((modifier_state & CLUTTER_CONTROL_MASK) &&
keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
if ((modifier_state & CLUTTER_MOD1_MASK) &&
keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
if ((modifier_state & CLUTTER_MOD2_MASK) &&
keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
if ((modifier_state & CLUTTER_MOD3_MASK) &&
keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
if ((modifier_state & CLUTTER_SUPER_MASK) &&
keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.super_mod);
if ((modifier_state & CLUTTER_MOD5_MASK) &&
keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
keyboard->last_modifier_state = modifier_state;
keyboard->modifier_state = new_state;
grab->interface->modifiers (grab,
serial,
depressed_mods,
0, /* latched_modes */
locked_mods,
0 /* group */);
new_state.mods_depressed,
new_state.mods_latched,
new_state.mods_locked,
new_state.group);
}
void
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event)
static gboolean
update_pressed_keys (MetaWaylandKeyboard *keyboard,
uint32_t evdev_code,
gboolean is_press)
{
gboolean state = event->type == CLUTTER_KEY_PRESS;
guint evdev_code;
uint32_t serial;
/* We can't do anything with the event if we can't get an evdev
keycode for it */
if (event->device == NULL ||
!clutter_input_device_keycode_to_evdev (event->device,
event->hardware_keycode,
&evdev_code))
return;
/* We want to ignore events that are sent because of auto-repeat. In
the Clutter event stream these appear as a single key press
event. We can detect that because the key will already have been
pressed */
if (state)
if (is_press)
{
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
/* Ignore the event if the key is already down */
/* We want to ignore events that are sent because of auto-repeat. In
the Clutter event stream these appear as a single key press
event. We can detect that because the key will already have been
pressed */
for (k = keyboard->keys.data; k < end; k++)
if (*k == evdev_code)
return;
return TRUE;
/* Otherwise add the key to the list of pressed keys */
k = wl_array_add (&keyboard->keys, sizeof (*k));
@@ -417,19 +428,56 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
}
g_warning ("unexpected key release event for key 0x%x", evdev_code);
return FALSE;
found:
(void) 0;
}
return FALSE;
}
gboolean
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event)
{
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
guint xkb_keycode, evdev_code;
uint32_t serial;
gboolean autorepeat;
gboolean handled;
xkb_keycode = event->hardware_keycode;
if (event->device == NULL ||
!clutter_input_device_keycode_to_evdev (event->device,
xkb_keycode, &evdev_code))
evdev_code = xkb_keycode - 8; /* What everyone is doing in practice... */
autorepeat = update_pressed_keys (keyboard, evdev_code, is_press);
meta_verbose ("Handling key %s%s event code %d\n",
is_press ? "press" : "release",
autorepeat ? " (autorepeat)" : "",
xkb_keycode);
if (autorepeat)
return FALSE;
serial = wl_display_next_serial (keyboard->display);
set_modifiers (keyboard, serial, event->modifier_state);
set_modifiers (keyboard, serial, (ClutterEvent*)event);
keyboard->grab->interface->key (keyboard->grab,
event->time,
evdev_code,
state);
handled = keyboard->grab->interface->key (keyboard->grab,
event->time,
evdev_code,
is_press);
if (handled)
meta_verbose ("Sent event to wayland client\n");
else
meta_verbose ("No wayland surface is focused, continuing normal operation\n");
return handled;
}
void
@@ -461,20 +509,35 @@ 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->modifiers.mods_depressed,
keyboard->modifiers.mods_latched,
keyboard->modifiers.mods_locked,
keyboard->modifiers.group);
wl_keyboard_send_enter (resource, serial, surface->resource,
&keyboard->keys);
/* If we're in a modal grab, the client is focused but doesn't see
modifiers or pressed keys (and fix that up when we exit the modal) */
if (keyboard->grab->interface == &modal_grab)
{
struct wl_array empty;
wl_array_init (&empty);
wl_keyboard_send_modifiers (resource, serial,
0, 0, 0, 0);
wl_keyboard_send_enter (resource, serial, surface->resource,
&empty);
}
else
{
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);
wl_keyboard_send_enter (resource, serial, surface->resource,
&keyboard->keys);
}
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
keyboard->focus_serial = serial;
}
keyboard->focus_resource = resource;
keyboard->focus = surface;
wl_signal_emit (&keyboard->focus_signal, keyboard);
}
void
@@ -510,3 +573,82 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
wl_list_remove (&keyboard->focus_listener.link);
wl_array_release (&keyboard->keys);
}
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp)
{
MetaWaylandKeyboardGrab *grab;
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
uint32_t serial;
meta_verbose ("Asked to acquire modal keyboard grab, timestamp %d\n", timestamp);
if (keyboard->grab != &keyboard->default_grab)
return FALSE;
if (keyboard->focus)
{
/* Fake key release events for the focused app */
serial = wl_display_next_serial (keyboard->display);
keyboard->grab->interface->modifiers (keyboard->grab,
serial,
0, 0, 0, 0);
for (k = keyboard->keys.data; k < end; k++)
{
keyboard->grab->interface->key (keyboard->grab,
timestamp,
*k, 0);
}
}
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
grab->interface = &modal_grab;
meta_wayland_keyboard_start_grab (keyboard, grab);
meta_verbose ("Acquired modal keyboard grab, timestamp %d\n", timestamp);
return TRUE;
}
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp)
{
MetaWaylandKeyboardGrab *grab;
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
uint32_t serial;
grab = keyboard->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_keyboard_end_grab (keyboard);
g_slice_free (MetaWaylandKeyboardGrab, grab);
if (keyboard->focus)
{
/* Fake key press events for the focused app */
serial = wl_display_next_serial (keyboard->display);
keyboard->grab->interface->modifiers (keyboard->grab,
serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
for (k = keyboard->keys.data; k < end; k++)
{
keyboard->grab->interface->key (keyboard->grab,
timestamp,
*k, 1);
}
}
meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp);
}

View File

@@ -48,13 +48,82 @@
#include <clutter/clutter.h>
#include <wayland-server.h>
#include "meta-wayland-seat.h"
struct _MetaWaylandKeyboardGrabInterface
{
gboolean (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
uint32_t key, uint32_t state);
void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group);
};
struct _MetaWaylandKeyboardGrab
{
const MetaWaylandKeyboardGrabInterface *interface;
MetaWaylandKeyboard *keyboard;
MetaWaylandSurface *focus;
uint32_t key;
};
typedef struct
{
struct xkb_keymap *keymap;
int keymap_fd;
size_t keymap_size;
char *keymap_area;
xkb_mod_index_t shift_mod;
xkb_mod_index_t caps_mod;
xkb_mod_index_t ctrl_mod;
xkb_mod_index_t alt_mod;
xkb_mod_index_t mod2_mod;
xkb_mod_index_t mod3_mod;
xkb_mod_index_t super_mod;
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;
MetaWaylandSurface *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
uint32_t focus_serial;
MetaWaylandKeyboardGrab *grab;
MetaWaylandKeyboardGrab default_grab;
uint32_t grab_key;
uint32_t grab_serial;
uint32_t grab_time;
struct wl_array keys;
MetaWaylandXkbState modifier_state;
struct wl_display *display;
struct xkb_context *xkb_context;
gboolean is_evdev;
MetaWaylandXkbInfo xkb_info;
struct xkb_rule_names xkb_names;
MetaWaylandKeyboardGrab input_method_grab;
struct wl_resource *input_method_resource;
};
gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display);
struct wl_display *display,
gboolean is_evdev);
void
gboolean
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event);
@@ -69,6 +138,13 @@ meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
void
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp);
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp);
void
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);

View File

@@ -43,10 +43,17 @@
#include "config.h"
#include <clutter/clutter.h>
#include <clutter/evdev/clutter-evdev.h>
#include <linux/input.h>
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include <string.h>
static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer);
static MetaWaylandSeat *
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
{
@@ -67,50 +74,79 @@ lose_pointer_focus (struct wl_listener *listener, void *data)
static void
default_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = grab->pointer;
if (pointer->button_count > 0)
return;
meta_wayland_pointer_set_focus (pointer, surface, x, y);
meta_wayland_pointer_set_focus (pointer, surface);
}
static void
default_grab_motion (MetaWaylandPointerGrab *grab,
uint32_t time, wl_fixed_t x, wl_fixed_t y)
const ClutterEvent *event)
{
struct wl_resource *resource;
resource = grab->pointer->focus_resource;
if (resource)
wl_pointer_send_motion (resource, time, x, y);
{
wl_fixed_t sx, sy;
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
grab->pointer->focus,
&sx, &sy);
wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy);
}
}
static void
default_grab_button (MetaWaylandPointerGrab *grab,
uint32_t time, uint32_t button, uint32_t state_w)
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = grab->pointer;
struct wl_resource *resource;
uint32_t serial;
enum wl_pointer_button_state state = state_w;
ClutterEventType event_type;
event_type = clutter_event_type (event);
resource = pointer->focus_resource;
if (resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t button;
uint32_t serial;
button = clutter_event_get_button (event);
switch (button)
{
/* The evdev input right and middle button numbers are swapped
relative to how Clutter numbers them */
case 2:
button = BTN_MIDDLE;
break;
case 3:
button = BTN_RIGHT;
break;
default:
button = button + BTN_LEFT - 1;
break;
}
serial = wl_display_next_serial (display);
wl_pointer_send_button (resource, serial, time, button, state_w);
wl_pointer_send_button (resource, serial,
clutter_event_get_time (event), button,
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
}
if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
meta_wayland_pointer_set_focus (pointer, pointer->current,
pointer->current_x, pointer->current_y);
if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
meta_wayland_pointer_set_focus (pointer, pointer->current);
}
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
@@ -119,20 +155,132 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
default_grab_button
};
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer)
/*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
*
* Copyright © 2006 Keith Packard
* Copyright 2010 Red Hat, Inc
*
*/
static gboolean
check_all_screen_monitors(MetaMonitorInfo *monitors,
unsigned n_monitors,
float x,
float y)
{
unsigned int i;
for (i = 0; i < n_monitors; i++)
{
MetaMonitorInfo *monitor = &monitors[i];
int left, right, top, bottom;
left = monitor->rect.x;
right = left + monitor->rect.width;
top = monitor->rect.y;
bottom = left + monitor->rect.height;
if ((x >= left) && (x < right) && (y >= top) && (y < bottom))
return TRUE;
}
return FALSE;
}
static void
constrain_all_screen_monitors (ClutterInputDevice *device,
MetaMonitorInfo *monitors,
unsigned n_monitors,
float *x,
float *y)
{
ClutterPoint current;
unsigned int i;
clutter_input_device_get_coords (device, NULL, &current);
/* if we're trying to escape, clamp to the CRTC we're coming from */
for (i = 0; i < n_monitors; i++)
{
MetaMonitorInfo *monitor = &monitors[i];
int left, right, top, bottom;
float nx, ny;
left = monitor->rect.x;
right = left + monitor->rect.width;
top = monitor->rect.y;
bottom = left + monitor->rect.height;
nx = current.x;
ny = current.y;
if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom))
{
if (*x < left)
*x = left;
if (*x >= right)
*x = right - 1;
if (*y < top)
*y = top;
if (*y >= bottom)
*y = bottom - 1;
return;
}
}
}
static void
pointer_constrain_callback (ClutterInputDevice *device,
guint32 time,
float *new_x,
float *new_y,
gpointer user_data)
{
MetaMonitorManager *monitor_manager;
MetaMonitorInfo *monitors;
unsigned int n_monitors;
gboolean ret;
monitor_manager = meta_monitor_manager_get ();
monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
/* if we're moving inside a monitor, we're fine */
ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y);
if (ret == TRUE)
return;
/* if we're trying to escape, clamp to the CRTC we're coming from */
constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
}
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
gboolean is_native)
{
ClutterDeviceManager *manager;
ClutterInputDevice *device;
ClutterPoint current;
memset (pointer, 0, sizeof *pointer);
wl_list_init (&pointer->resource_list);
pointer->focus_listener.notify = lose_pointer_focus;
pointer->default_grab.interface = &default_pointer_grab_interface;
pointer->default_grab.pointer = pointer;
pointer->grab = &pointer->default_grab;
wl_signal_init (&pointer->focus_signal);
/* FIXME: Pick better co-ords. */
pointer->x = wl_fixed_from_int (100);
pointer->y = wl_fixed_from_int (100);
manager = clutter_device_manager_get_default ();
device = clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
if (is_native)
clutter_evdev_set_pointer_constrain_callback (manager, pointer_constrain_callback,
pointer, NULL);
clutter_input_device_get_coords (device, NULL, &current);
pointer->x = wl_fixed_from_double (current.x);
pointer->y = wl_fixed_from_double (current.y);
}
void
@@ -162,8 +310,7 @@ find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t sx, wl_fixed_t sy)
MetaWaylandSurface *surface)
{
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandKeyboard *kbd = &seat->keyboard;
@@ -186,7 +333,10 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
wl_fixed_t sx, sy;
serial = wl_display_next_serial (display);
if (kbd)
{
kr = find_resource_for_surface (&kbd->resource_list, surface);
@@ -194,12 +344,14 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
{
wl_keyboard_send_modifiers (kr,
serial,
kbd->modifiers.mods_depressed,
kbd->modifiers.mods_latched,
kbd->modifiers.mods_locked,
kbd->modifiers.group);
kbd->modifier_state.mods_depressed,
kbd->modifier_state.mods_latched,
kbd->modifier_state.mods_locked,
kbd->modifier_state.group);
}
}
meta_wayland_pointer_get_relative_coordinates (pointer, surface, &sx, &sy);
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
pointer->focus_serial = serial;
@@ -207,8 +359,6 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
pointer->focus_resource = resource;
pointer->focus = surface;
pointer->default_grab.focus = surface;
wl_signal_emit (&pointer->focus_signal, pointer);
}
void
@@ -222,8 +372,7 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
grab->pointer = pointer;
if (pointer->current)
interface->focus (pointer->grab, pointer->current,
pointer->current_x, pointer->current_y);
interface->focus (pointer->grab, pointer->current, NULL);
}
void
@@ -233,8 +382,7 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
pointer->grab = &pointer->default_grab;
interface = pointer->grab->interface;
interface->focus (pointer->grab, pointer->current,
pointer->current_x, pointer->current_y);
interface->focus (pointer->grab, pointer->current, NULL);
}
static void
@@ -262,3 +410,245 @@ 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,
const ClutterEvent *event)
{
}
static void
modal_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
}
static void
modal_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
}
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);
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);
}
/* Called when the focused resource is destroyed */
void
meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer)
{
if (pointer->grab == &pointer->default_grab)
{
/* The surface was destroyed, but had the implicit pointer grab.
Bypass the grab interface. */
g_assert (pointer->button_count > 0);
/* Note: we focus the NULL interface, not the current one, because
we have button down, and the clients would be confused if the
pointer enters the surface.
*/
meta_wayland_pointer_set_focus (pointer, NULL);
}
}
typedef struct {
MetaWaylandPointerGrab generic;
struct wl_client *grab_client;
struct wl_list all_popups;
} MetaWaylandPopupGrab;
typedef struct {
MetaWaylandPopupGrab *grab;
MetaWaylandSurface *surface;
struct wl_listener surface_destroy_listener;
struct wl_list link;
} MetaWaylandPopup;
static void
popup_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
/* Popup grabs are in owner-events mode (ie, events for the same client
are reported as normal) */
if (wl_resource_get_client (surface->resource) == popup_grab->grab_client)
default_grab_focus (grab, surface, event);
else
meta_wayland_pointer_set_focus (grab->pointer, NULL);
}
static void
popup_grab_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
default_grab_motion (grab, event);
}
static void
popup_grab_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
MetaWaylandPointer *pointer = grab->pointer;
if (pointer->focus_resource)
{
/* This is ensured by popup_grab_focus */
g_assert (wl_resource_get_client (pointer->focus_resource) == popup_grab->grab_client);
default_grab_button (grab, event);
}
else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE &&
pointer->button_count == 0)
meta_wayland_pointer_end_popup_grab (grab->pointer);
}
static MetaWaylandPointerGrabInterface popup_grab_interface = {
popup_grab_focus,
popup_grab_motion,
popup_grab_button
};
static void
meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
{
MetaWaylandPopupGrab *popup_grab;
MetaWaylandPopup *popup, *tmp;
popup_grab = (MetaWaylandPopupGrab*)pointer->grab;
g_assert (popup_grab->generic.interface == &popup_grab_interface);
wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link)
{
MetaWaylandSurfaceExtension *shell_surface = popup->surface->shell_surface;
wl_shell_surface_send_popup_done (shell_surface->resource);
wl_list_remove (&popup->surface_destroy_listener.link);
wl_list_remove (&popup->link);
g_slice_free (MetaWaylandPopup, popup);
}
meta_wayland_pointer_end_grab (pointer);
g_slice_free (MetaWaylandPopupGrab, popup_grab);
}
static void
on_popup_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandPopup *popup =
wl_container_of (listener, popup, surface_destroy_listener);
MetaWaylandPopupGrab *popup_grab = popup->grab;
wl_list_remove (&popup->link);
g_slice_free (MetaWaylandPopup, popup);
if (wl_list_empty (&popup_grab->all_popups))
meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer);
}
gboolean
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
MetaWaylandPopupGrab *grab;
MetaWaylandPopup *popup;
if (pointer->grab != &pointer->default_grab)
{
if (pointer->grab->interface == &popup_grab_interface)
{
grab = (MetaWaylandPopupGrab*)pointer->grab;
if (wl_resource_get_client (surface->resource) != grab->grab_client)
return FALSE;
}
return FALSE;
}
if (pointer->grab == &pointer->default_grab)
{
grab = g_slice_new0 (MetaWaylandPopupGrab);
grab->generic.interface = &popup_grab_interface;
grab->generic.pointer = pointer;
grab->grab_client = wl_resource_get_client (surface->resource);
wl_list_init (&grab->all_popups);
meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
}
else
grab = (MetaWaylandPopupGrab*)pointer->grab;
popup = g_slice_new0 (MetaWaylandPopup);
popup->grab = grab;
popup->surface = surface;
popup->surface_destroy_listener.notify = on_popup_surface_destroy;
wl_resource_add_destroy_listener (surface->resource, &popup->surface_destroy_listener);
wl_list_insert (&grab->all_popups, &popup->link);
return TRUE;
}
void
meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t *sx,
wl_fixed_t *sy)
{
float xf = 0.0f, yf = 0.0f;
if (surface->window)
{
ClutterActor *actor =
CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
if (actor)
clutter_actor_transform_stage_point (actor,
wl_fixed_to_double (pointer->x),
wl_fixed_to_double (pointer->y),
&xf, &yf);
}
*sx = wl_fixed_from_double (xf);
*sy = wl_fixed_from_double (yf);
}

View File

@@ -22,19 +22,65 @@
#include <wayland-server.h>
#include "meta-wayland-seat.h"
#include <glib.h>
#include "meta-wayland-types.h"
struct _MetaWaylandPointerGrabInterface
{
void (*focus) (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
const ClutterEvent *event);
void (*motion) (MetaWaylandPointerGrab *grab,
const ClutterEvent *event);
void (*button) (MetaWaylandPointerGrab *grab,
const ClutterEvent *event);
};
struct _MetaWaylandPointerGrab
{
const MetaWaylandPointerGrabInterface *interface;
MetaWaylandPointer *pointer;
};
struct _MetaWaylandPointer
{
struct wl_list resource_list;
MetaWaylandSurface *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
guint32 focus_serial;
guint32 click_serial;
MetaWaylandPointerGrab *grab;
MetaWaylandPointerGrab default_grab;
wl_fixed_t grab_x, grab_y;
wl_fixed_t focus_x, focus_y;
guint32 grab_button;
guint32 grab_serial;
guint32 grab_time;
wl_fixed_t x, y; /* TODO: remove, use ClutterInputDevice instead */
MetaWaylandSurface *current;
struct wl_listener current_listener;
wl_fixed_t current_x, current_y;
guint32 button_count;
};
void
meta_wayland_pointer_init (MetaWaylandPointer *pointer);
meta_wayland_pointer_init (MetaWaylandPointer *pointer,
gboolean is_native);
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t sx,
wl_fixed_t sy);
MetaWaylandSurface *surface);
void
meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
MetaWaylandPointerGrab *grab);
@@ -42,8 +88,23 @@ 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);
gboolean
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *popup);
void
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);
void
meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t *x,
wl_fixed_t *y);
#endif /* __META_WAYLAND_POINTER_H__ */

View File

@@ -28,43 +28,13 @@
#include <cairo.h>
#include "window-private.h"
#include "meta-weston-launch.h"
#include <meta/meta-cursor-tracker.h>
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
typedef struct _MetaWaylandSeat MetaWaylandSeat;
typedef struct _MetaWaylandPointer MetaWaylandPointer;
typedef struct _MetaWaylandPointerGrab MetaWaylandPointerGrab;
typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface;
typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard;
typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab;
typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface;
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
typedef struct _MetaWaylandDataSource MetaWaylandDataSource;
typedef struct
{
struct wl_resource *resource;
struct wl_signal destroy_signal;
struct wl_listener destroy_listener;
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;
uint32_t busy_count;
} MetaWaylandBuffer;
typedef struct
{
MetaWaylandBuffer *buffer;
struct wl_listener destroy_listener;
} MetaWaylandBufferReference;
#include "meta-wayland-types.h"
#include "meta-wayland-versions.h"
#include "meta-wayland-surface.h"
#include "meta-wayland-seat.h"
typedef struct
{
@@ -72,46 +42,6 @@ typedef struct
cairo_region_t *region;
} MetaWaylandRegion;
struct _MetaWaylandSurface
{
struct wl_resource *resource;
MetaWaylandCompositor *compositor;
guint32 xid;
int x;
int y;
MetaWaylandBufferReference buffer_ref;
MetaWindow *window;
gboolean has_shell_surface;
/* All the pending state, that wl_surface.commit will apply. */
struct
{
/* wl_surface.attach */
gboolean newly_attached;
MetaWaylandBuffer *buffer;
struct wl_listener buffer_destroy_listener;
int32_t sx;
int32_t sy;
/* wl_surface.damage */
cairo_region_t *damage;
/* wl_surface.frame */
struct wl_list frame_callback_list;
} pending;
};
#ifndef HAVE_META_WAYLAND_SURFACE_TYPE
typedef struct _MetaWaylandSurface MetaWaylandSurface;
#endif
typedef struct
{
MetaWaylandSurface *surface;
struct wl_resource *resource;
struct wl_listener surface_destroy_listener;
} MetaWaylandShellSurface;
typedef struct
{
GSource source;
@@ -132,6 +62,7 @@ typedef struct
struct _MetaWaylandCompositor
{
struct wl_display *wayland_display;
char *display_name;
struct wl_event_loop *wayland_loop;
GMainLoop *init_loop;
ClutterActor *stage;
@@ -148,6 +79,9 @@ struct _MetaWaylandCompositor
struct wl_client *xwayland_client;
struct wl_resource *xserver_resource;
MetaLauncher *launcher;
int drm_fd;
MetaWaylandSeat *seat;
/* This surface is only used to keep drag of the implicit grab when
@@ -159,173 +93,6 @@ struct _MetaWaylandCompositor
guint32 implicit_grab_button;
};
struct _MetaWaylandPointerGrabInterface
{
void (*focus) (MetaWaylandPointerGrab * grab,
MetaWaylandSurface * surface, wl_fixed_t x, wl_fixed_t y);
void (*motion) (MetaWaylandPointerGrab * grab,
uint32_t time, wl_fixed_t x, wl_fixed_t y);
void (*button) (MetaWaylandPointerGrab * grab,
uint32_t time, uint32_t button, uint32_t state);
};
struct _MetaWaylandPointerGrab
{
const MetaWaylandPointerGrabInterface *interface;
MetaWaylandPointer *pointer;
MetaWaylandSurface *focus;
wl_fixed_t x, y;
};
struct _MetaWaylandPointer
{
struct wl_list resource_list;
MetaWaylandSurface *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
guint32 focus_serial;
struct wl_signal focus_signal;
MetaWaylandPointerGrab *grab;
MetaWaylandPointerGrab default_grab;
wl_fixed_t grab_x, grab_y;
guint32 grab_button;
guint32 grab_serial;
guint32 grab_time;
wl_fixed_t x, y;
MetaWaylandSurface *current;
struct wl_listener current_listener;
wl_fixed_t current_x, current_y;
guint32 button_count;
};
struct _MetaWaylandKeyboardGrabInterface
{
void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
uint32_t key, uint32_t state);
void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group);
};
struct _MetaWaylandKeyboardGrab
{
const MetaWaylandKeyboardGrabInterface *interface;
MetaWaylandKeyboard *keyboard;
MetaWaylandSurface *focus;
uint32_t key;
};
typedef struct
{
struct xkb_keymap *keymap;
int keymap_fd;
size_t keymap_size;
char *keymap_area;
xkb_mod_index_t shift_mod;
xkb_mod_index_t caps_mod;
xkb_mod_index_t ctrl_mod;
xkb_mod_index_t alt_mod;
xkb_mod_index_t mod2_mod;
xkb_mod_index_t mod3_mod;
xkb_mod_index_t super_mod;
xkb_mod_index_t mod5_mod;
} MetaWaylandXkbInfo;
struct _MetaWaylandKeyboard
{
struct wl_list resource_list;
MetaWaylandSurface *focus;
struct wl_resource *focus_resource;
struct wl_listener focus_listener;
uint32_t focus_serial;
struct wl_signal focus_signal;
MetaWaylandKeyboardGrab *grab;
MetaWaylandKeyboardGrab default_grab;
uint32_t grab_key;
uint32_t grab_serial;
uint32_t grab_time;
struct wl_array keys;
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;
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
{
struct wl_resource *resource;
MetaWaylandDataSource *source;
struct wl_listener source_destroy_listener;
};
struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
void (*accept) (MetaWaylandDataSource * source,
uint32_t serial, const char *mime_type);
void (*send) (MetaWaylandDataSource * source,
const char *mime_type, int32_t fd);
void (*cancel) (MetaWaylandDataSource * source);
};
struct _MetaWaylandSeat
{
struct wl_list base_resource_list;
struct wl_signal destroy_signal;
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
struct wl_listener selection_data_source_listener;
struct wl_signal selection_signal;
struct wl_list drag_resource_list;
struct wl_client *drag_client;
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
MetaWaylandSurface *drag_focus;
struct wl_resource *drag_focus_resource;
struct wl_listener drag_focus_listener;
MetaWaylandPointerGrab drag_grab;
MetaWaylandSurface *drag_surface;
struct wl_listener drag_icon_listener;
struct wl_signal drag_icon_signal;
MetaWaylandPointer pointer;
MetaWaylandKeyboard keyboard;
struct wl_display *display;
MetaCursorTracker *cursor_tracker;
MetaWaylandSurface *sprite;
int hotspot_x, hotspot_y;
struct wl_listener sprite_destroy_listener;
ClutterActor *current_stage;
};
void meta_wayland_init (void);
void meta_wayland_finalize (void);
@@ -338,6 +105,13 @@ void meta_wayland_compositor_repick (MetaWaylandComp
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
MetaWindow *window);
void meta_wayland_surface_free (MetaWaylandSurface *surface);
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
gboolean meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor);
MetaWaylandBuffer * meta_wayland_buffer_from_resource (struct wl_resource *resource);
void meta_wayland_buffer_reference (MetaWaylandBufferReference *ref,
MetaWaylandBuffer *buffer);
#endif /* META_WAYLAND_PRIVATE_H */

View File

@@ -47,37 +47,12 @@ unbind_resource (struct wl_resource *resource)
wl_list_remove (wl_resource_get_link (resource));
}
static void
transform_stage_point_fixed (MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y,
wl_fixed_t *sx,
wl_fixed_t *sy)
{
float xf = 0.0f, yf = 0.0f;
if (surface->window)
{
ClutterActor *actor =
CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
if (actor)
clutter_actor_transform_stage_point (actor,
wl_fixed_to_double (x),
wl_fixed_to_double (y),
&xf, &yf);
}
*sx = wl_fixed_from_double (xf);
*sy = wl_fixed_from_double (yf);
}
static void
pointer_unmap_sprite (MetaWaylandSeat *seat)
{
if (seat->cursor_tracker)
{
meta_cursor_tracker_set_sprite (seat->cursor_tracker,
meta_cursor_tracker_set_buffer (seat->cursor_tracker,
NULL, 0, 0);
if (seat->current_stage)
@@ -95,29 +70,20 @@ pointer_unmap_sprite (MetaWaylandSeat *seat)
void
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
{
ClutterBackend *backend;
CoglContext *context;
struct wl_resource *buffer;
CoglTexture2D *texture;
if (seat->cursor_tracker == NULL)
return;
backend = clutter_get_default_backend ();
context = clutter_backend_get_cogl_context (backend);
buffer = seat->sprite->buffer_ref.buffer->resource;
texture = cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL);
meta_cursor_tracker_set_sprite (seat->cursor_tracker,
texture,
meta_cursor_tracker_set_buffer (seat->cursor_tracker,
buffer,
seat->hotspot_x,
seat->hotspot_y);
if (seat->current_stage)
meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
CLUTTER_ACTOR (seat->current_stage));
cogl_object_unref (texture);
}
static void
@@ -175,26 +141,14 @@ seat_get_pointer (struct wl_client *client,
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
struct wl_resource *cr;
cr = wl_client_add_object (client, &wl_pointer_interface,
&pointer_interface, id, seat);
cr = wl_resource_create (client, &wl_pointer_interface,
MIN (META_WL_POINTER_VERSION, wl_resource_get_version (resource)), id);
wl_resource_set_implementation (cr, &pointer_interface, seat, unbind_resource);
wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr));
wl_resource_set_destructor (cr, unbind_resource);
if (seat->pointer.focus &&
wl_resource_get_client (seat->pointer.focus->resource) == client)
{
MetaWaylandSurface *surface;
wl_fixed_t sx, sy;
surface = (MetaWaylandSurface *) seat->pointer.focus;
transform_stage_point_fixed (surface,
seat->pointer.x,
seat->pointer.y,
&sx, &sy);
meta_wayland_pointer_set_focus (&seat->pointer,
seat->pointer.focus,
sx, sy);
}
meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus);
}
static void
@@ -205,9 +159,10 @@ seat_get_keyboard (struct wl_client *client,
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
struct wl_resource *cr;
cr = wl_client_add_object (client, &wl_keyboard_interface, NULL, id, seat);
cr = wl_resource_create (client, &wl_keyboard_interface,
MIN (META_WL_KEYBOARD_VERSION, wl_resource_get_version (resource)), id);
wl_resource_set_implementation (cr, NULL, seat, unbind_resource);
wl_list_insert (&seat->keyboard.resource_list, wl_resource_get_link (cr));
wl_resource_set_destructor (cr, unbind_resource);
wl_keyboard_send_keymap (cr,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
@@ -217,8 +172,7 @@ seat_get_keyboard (struct wl_client *client,
if (seat->keyboard.focus &&
wl_resource_get_client (seat->keyboard.focus->resource) == client)
{
meta_wayland_keyboard_set_focus (&seat->keyboard,
seat->keyboard.focus);
meta_wayland_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus);
meta_wayland_data_device_set_keyboard_focus (seat);
}
}
@@ -248,17 +202,17 @@ bind_seat (struct wl_client *client,
MetaWaylandSeat *seat = data;
struct wl_resource *resource;
resource = wl_client_add_object (client,
&wl_seat_interface,
&seat_interface,
id,
data);
resource = wl_resource_create (client, &wl_seat_interface,
MIN (META_WL_SEAT_VERSION, version), id);
wl_resource_set_implementation (resource, &seat_interface, seat, unbind_resource);
wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource));
wl_resource_set_destructor (resource, unbind_resource);
wl_seat_send_capabilities (resource,
WL_SEAT_CAPABILITY_POINTER |
WL_SEAT_CAPABILITY_KEYBOARD);
if (version >= META_WL_SEAT_HAS_NAME)
wl_seat_send_name (resource, "seat0");
}
static void
@@ -271,21 +225,18 @@ pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
}
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display)
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native)
{
MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
wl_signal_init (&seat->destroy_signal);
seat->selection_data_source = NULL;
wl_list_init (&seat->base_resource_list);
wl_signal_init (&seat->selection_signal);
wl_list_init (&seat->drag_resource_list);
wl_signal_init (&seat->drag_icon_signal);
wl_list_init (&seat->data_device_resource_list);
meta_wayland_pointer_init (&seat->pointer);
meta_wayland_pointer_init (&seat->pointer, is_native);
meta_wayland_keyboard_init (&seat->keyboard, display);
meta_wayland_keyboard_init (&seat->keyboard, display, is_native);
seat->display = display;
@@ -296,13 +247,13 @@ meta_wayland_seat_new (struct wl_display *display)
seat->hotspot_x = 16;
seat->hotspot_y = 16;
wl_display_add_global (display, &wl_seat_interface, seat, bind_seat);
wl_global_create (display, &wl_seat_interface, META_WL_SEAT_VERSION, seat, bind_seat);
return seat;
}
static void
notify_motion (MetaWaylandSeat *seat,
notify_motion (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = &seat->pointer;
@@ -312,91 +263,64 @@ notify_motion (MetaWaylandSeat *seat,
pointer->x = wl_fixed_from_double (x);
pointer->y = wl_fixed_from_double (y);
meta_wayland_seat_repick (seat,
clutter_event_get_time (event),
clutter_event_get_source (event));
meta_wayland_seat_repick (seat, event);
pointer->grab->interface->motion (pointer->grab,
clutter_event_get_time (event),
pointer->grab->x,
pointer->grab->y);
pointer->grab->interface->motion (pointer->grab, event);
}
static void
handle_motion_event (MetaWaylandSeat *seat,
const ClutterMotionEvent *event)
handle_motion_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
notify_motion (seat, (const ClutterEvent *) event);
notify_motion (seat, event);
}
static void
handle_button_event (MetaWaylandSeat *seat,
const ClutterButtonEvent *event)
handle_button_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = &seat->pointer;
gboolean state = event->type == CLUTTER_BUTTON_PRESS;
uint32_t button;
MetaWaylandSurface *surface;
notify_motion (seat, (const ClutterEvent *) event);
notify_motion (seat, event);
switch (event->button)
if (state && pointer->button_count == 1)
{
/* The evdev input right and middle button numbers are swapped
relative to how Clutter numbers them */
case 2:
button = BTN_MIDDLE;
break;
button = clutter_event_get_button (event);
pointer->grab_button = button;
pointer->grab_time = clutter_event_get_time (event);
pointer->grab_x = pointer->x;
pointer->grab_y = pointer->y;
case 3:
button = BTN_RIGHT;
break;
default:
button = event->button + BTN_LEFT - 1;
break;
/* FIXME: synth a XI2 event and handle in display.c */
surface = pointer->current;
if (button == CLUTTER_BUTTON_PRIMARY &&
surface &&
surface->window &&
surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
meta_window_raise (surface->window);
}
}
if (state)
{
if (pointer->button_count == 0)
{
MetaWaylandSurface *surface = pointer->current;
pointer->grab_button = button;
pointer->grab_time = event->time;
pointer->grab_x = pointer->x;
pointer->grab_y = pointer->y;
if (button == BTN_LEFT &&
surface &&
surface->window &&
surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
{
meta_window_raise (surface->window);
}
}
pointer->button_count++;
}
else
pointer->button_count--;
pointer->grab->interface->button (pointer->grab, event->time, button, state);
pointer->grab->interface->button (pointer->grab, event);
if (pointer->button_count == 1)
pointer->grab_serial = wl_display_get_serial (seat->display);
}
static void
handle_scroll_event (MetaWaylandSeat *seat,
const ClutterScrollEvent *event)
handle_scroll_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
enum wl_pointer_axis axis;
wl_fixed_t value;
notify_motion (seat, (const ClutterEvent *) event);
notify_motion (seat, event);
switch (event->direction)
switch (clutter_event_get_scroll_direction (event))
{
case CLUTTER_SCROLL_UP:
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
@@ -424,41 +348,64 @@ handle_scroll_event (MetaWaylandSeat *seat,
if (seat->pointer.focus_resource)
wl_pointer_send_axis (seat->pointer.focus_resource,
event->time,
clutter_event_get_time (event),
axis,
value);
}
void
static int
count_buttons (const ClutterEvent *event)
{
static gint maskmap[5] =
{
CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON2_MASK, CLUTTER_BUTTON3_MASK,
CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK
};
ClutterModifierType mod_mask;
int i, count;
mod_mask = clutter_event_get_state (event);
count = 0;
for (i = 0; i < 5; i++)
{
if (mod_mask & maskmap[i])
count++;
}
return count;
}
gboolean
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
seat->pointer.button_count = count_buttons (event);
switch (event->type)
{
case CLUTTER_MOTION:
handle_motion_event (seat,
(const ClutterMotionEvent *) event);
handle_motion_event (seat, event);
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
handle_button_event (seat,
(const ClutterButtonEvent *) event);
handle_button_event (seat, event);
break;
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
meta_wayland_keyboard_handle_event (&seat->keyboard,
(const ClutterKeyEvent *) event);
break;
return meta_wayland_keyboard_handle_event (&seat->keyboard,
(const ClutterKeyEvent *) event);
case CLUTTER_SCROLL:
handle_scroll_event (seat, (const ClutterScrollEvent *) event);
handle_scroll_event (seat, event);
break;
default:
break;
}
return FALSE;
}
static void
@@ -481,14 +428,18 @@ update_pointer_position_for_actor (MetaWaylandPointer *pointer,
case Clutter will have already performed a pick so we can avoid
redundantly doing another one */
void
meta_wayland_seat_repick (MetaWaylandSeat *seat,
uint32_t time,
ClutterActor *actor)
meta_wayland_seat_repick (MetaWaylandSeat *seat,
const ClutterEvent *for_event)
{
ClutterActor *actor = NULL;
MetaWaylandPointer *pointer = &seat->pointer;
MetaWaylandSurface *surface = NULL;
if (actor == NULL && seat->current_stage)
if (for_event)
{
actor = clutter_event_get_source (for_event);
}
else if (seat->current_stage)
{
ClutterStage *stage = CLUTTER_STAGE (seat->current_stage);
actor = clutter_stage_get_actor_at_pos (stage,
@@ -526,16 +477,8 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
const MetaWaylandPointerGrabInterface *interface =
pointer->grab->interface;
interface->focus (pointer->grab,
surface,
pointer->current_x, pointer->current_y);
surface, for_event);
}
if (pointer->grab->focus)
transform_stage_point_fixed (pointer->grab->focus,
pointer->x,
pointer->y,
&pointer->grab->x,
&pointer->grab->y);
}
void
@@ -546,7 +489,5 @@ meta_wayland_seat_free (MetaWaylandSeat *seat)
meta_wayland_pointer_release (&seat->pointer);
meta_wayland_keyboard_release (&seat->keyboard);
wl_signal_emit (&seat->destroy_signal, seat);
g_slice_free (MetaWaylandSeat, seat);
}

View File

@@ -27,19 +27,63 @@
#include <clutter/clutter.h>
#include <glib.h>
#include "meta-wayland-private.h"
#include <meta/meta-cursor-tracker.h>
#include "meta-wayland-types.h"
#include "meta-wayland-keyboard.h"
#include "meta-wayland-pointer.h"
struct _MetaWaylandDataOffer
{
struct wl_resource *resource;
MetaWaylandDataSource *source;
struct wl_listener source_destroy_listener;
};
struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
void (*accept) (MetaWaylandDataSource * source,
uint32_t serial, const char *mime_type);
void (*send) (MetaWaylandDataSource * source,
const char *mime_type, int32_t fd);
void (*cancel) (MetaWaylandDataSource * source);
};
struct _MetaWaylandSeat
{
struct wl_list base_resource_list;
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list data_device_resource_list;
MetaWaylandPointer pointer;
MetaWaylandKeyboard keyboard;
struct wl_display *display;
MetaCursorTracker *cursor_tracker;
MetaWaylandSurface *sprite;
int hotspot_x, hotspot_y;
struct wl_listener sprite_destroy_listener;
ClutterActor *current_stage;
};
MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display);
meta_wayland_seat_new (struct wl_display *display,
gboolean is_native);
void
gboolean
meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
const ClutterEvent *event);
void
meta_wayland_seat_repick (MetaWaylandSeat *seat,
uint32_t time,
ClutterActor *actor);
meta_wayland_seat_repick (MetaWaylandSeat *seat,
const ClutterEvent *for_event);
void
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat);

View File

@@ -26,6 +26,7 @@
#include <cogl/cogl-wayland-server.h>
#include "meta-wayland-stage.h"
#include "meta-wayland-private.h"
#include "meta/meta-window-actor.h"
#include "meta/meta-shaped-texture.h"
#include "meta-cursor-tracker-private.h"

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